Compare commits
13 Commits
1.0
...
22f9a8a1a6
| Author | SHA1 | Date | |
|---|---|---|---|
| 22f9a8a1a6 | |||
| 7e76c4813d | |||
| 8967846657 | |||
| c58b6c5624 | |||
| 5f5e24fa9c | |||
| cdffa1b50b | |||
| eec9e25e12 | |||
| 3b4853acda | |||
| cea13986f0 | |||
| 3641ffdad9 | |||
| 7fa68792fb | |||
| ebdd35b1e1 | |||
| b986bfde39 |
@@ -1,13 +1,44 @@
|
||||
#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
|
||||
: device(other.device), volumeInterface(other.volumeInterface), meterInterface(other.meterInterface),
|
||||
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.volumeInterface = nullptr;
|
||||
@@ -25,6 +56,8 @@ AudioDevice& AudioDevice::operator=(AudioDevice&& other) noexcept
|
||||
this->isDefaultConsole = other.isDefaultConsole;
|
||||
this->isDefaultMedia = other.isDefaultMedia;
|
||||
this->isDefaultCommunication = other.isDefaultCommunication;
|
||||
this->minVolumeDb = other.minVolumeDb;
|
||||
this->maxVolumeDb = other.maxVolumeDb;
|
||||
|
||||
other.device = nullptr;
|
||||
other.volumeInterface = nullptr;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <mmdeviceapi.h>
|
||||
#include "AudioNotificationListener.h"
|
||||
|
||||
#include <endpointvolume.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "AudioNotificationListener.h"
|
||||
#include <unordered_map>
|
||||
|
||||
class AudioDevice {
|
||||
public:
|
||||
@@ -14,11 +16,13 @@ public:
|
||||
std::wstring id = {};
|
||||
std::string name = {};
|
||||
unsigned long state = {};
|
||||
bool isDefaultConsole = {};
|
||||
bool isDefaultMedia = {};
|
||||
bool isDefaultCommunication = {};
|
||||
bool isDefaultConsole = false;
|
||||
bool isDefaultMedia = false;
|
||||
bool isDefaultCommunication = false;
|
||||
float minVolumeDb = 0.f;
|
||||
float maxVolumeDb = 0.f;
|
||||
|
||||
AudioDevice();
|
||||
AudioDevice(IMMDevice* device, LPCWSTR deviceId);
|
||||
AudioDevice(AudioDevice&& other) noexcept;
|
||||
AudioDevice& operator=(AudioDevice&& other) noexcept;
|
||||
~AudioDevice();
|
||||
@@ -42,13 +46,16 @@ public:
|
||||
bool autostart = false;
|
||||
bool docked = false;
|
||||
bool showDisabledDevices = false;
|
||||
std::vector<std::string> taskNames = {};
|
||||
std::unordered_map<std::string, std::vector<time_t>> tasks = {};
|
||||
};
|
||||
|
||||
class ApplicationData {
|
||||
public:
|
||||
ApplicationSettings settings = {};
|
||||
size_t checklistLength = 0;
|
||||
std::shared_ptr<AudioData> audioData = std::make_shared<AudioData>();
|
||||
|
||||
ApplicationData(const ApplicationData&) = delete;
|
||||
ApplicationData& operator=(const ApplicationData&) = delete;
|
||||
//ApplicationData(const ApplicationData&) = delete;
|
||||
//ApplicationData& operator=(const ApplicationData&) = delete;
|
||||
};
|
||||
|
||||
@@ -7,26 +7,22 @@
|
||||
// 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(lib, "comctl32.lib")
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <shellapi.h>
|
||||
#include <commctrl.h>
|
||||
#include <strsafe.h>
|
||||
#pragma comment(lib, "rpcrt4.lib")
|
||||
|
||||
#include "Util.h"
|
||||
#include "AudioApi.h"
|
||||
#include "Settings.h"
|
||||
#include "resource.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;
|
||||
UINT const WMAPP_HIDEFLYOUT = WM_APP + 2;
|
||||
#define MAX_FONT_PATH_LENGTH 2048
|
||||
|
||||
// Globals for use in callbacks
|
||||
DrawData* gDrawData;
|
||||
@@ -36,6 +32,13 @@ bool isHidden = false;
|
||||
|
||||
int main()
|
||||
{
|
||||
std::wstring appDir;
|
||||
getAppDir(appDir);
|
||||
if (_wchdir(appDir.c_str()) != 0)
|
||||
{
|
||||
std::cout << "Failed to set working dir." << std::endl;
|
||||
}
|
||||
|
||||
ApplicationData applicationData{};
|
||||
ImGuiCallbacks callbacks{};
|
||||
|
||||
@@ -43,79 +46,40 @@ int main()
|
||||
callbacks.drawFunc = std::bind(draw, 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)
|
||||
{
|
||||
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 :(
|
||||
gDrawData = &drawData;
|
||||
gAppData = &appData;
|
||||
|
||||
// Load text font
|
||||
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
|
||||
static const ImWchar icons_ranges[] = { 0xEA01, 0xF2DF, 0 };
|
||||
ImFontConfig icons_config;
|
||||
icons_config.MergeMode = 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
|
||||
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
|
||||
initShell(drawData);
|
||||
initSettings(drawData, appData);
|
||||
|
||||
// Set up audio device api
|
||||
initAudio(appData);
|
||||
}
|
||||
|
||||
@@ -123,11 +87,6 @@ void draw(DrawData& drawData, ApplicationData& appData)
|
||||
{
|
||||
justDocked = false;
|
||||
|
||||
// sad :(
|
||||
gDrawData = &drawData;
|
||||
gAppData = &appData;
|
||||
|
||||
// Actual Drawing
|
||||
if (isHidden)
|
||||
{
|
||||
glfwWaitEvents();
|
||||
@@ -140,17 +99,24 @@ void draw(DrawData& drawData, ApplicationData& appData)
|
||||
// Menu Bar
|
||||
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
|
||||
ImGui::SetNextWindowPos(ImVec2(0, customYCursor));
|
||||
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.;
|
||||
|
||||
// Recording devices
|
||||
ImGui::SetNextWindowPos(ImVec2(0, customYCursor));
|
||||
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
|
||||
drawData.window_size.y = customYCursor;
|
||||
@@ -165,11 +131,7 @@ void draw(DrawData& drawData, ApplicationData& appData)
|
||||
|
||||
void cleanup(DrawData& drawData, ApplicationData& appData)
|
||||
{
|
||||
// Remove tray icon
|
||||
NOTIFYICONDATA nid = { sizeof(nid) };
|
||||
nid.uFlags = NIF_GUID;
|
||||
nid.guidItem = __uuidof(TrayGUID);
|
||||
bool test = Shell_NotifyIcon(NIM_DELETE, &nid);
|
||||
cleanupShell(drawData);
|
||||
}
|
||||
|
||||
ImVec2 menuBar(DrawData& drawData, ApplicationData& appData)
|
||||
@@ -181,9 +143,7 @@ ImVec2 menuBar(DrawData& drawData, ApplicationData& appData)
|
||||
{
|
||||
if (ImGui::BeginMenu("Settings"))
|
||||
{
|
||||
bool prevDocked = appData.settings.docked;
|
||||
ImGui::Checkbox("Docked", &appData.settings.docked);
|
||||
if (appData.settings.docked != prevDocked)
|
||||
if (ImGui::Checkbox("Docked", &appData.settings.docked))
|
||||
{
|
||||
closeMenu = true;
|
||||
updateDocked(drawData, appData);
|
||||
@@ -212,13 +172,13 @@ ImVec2 menuBar(DrawData& drawData, ApplicationData& appData)
|
||||
{
|
||||
ImVec2 availableSpace = ImGui::GetContentRegionAvail();
|
||||
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);
|
||||
}
|
||||
if (ImGui::SmallButton("x"))
|
||||
if (ImGui::SmallButton(ICON_CLOSE_FILL))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (ImGui::Begin(title, 0, ImGuiWindowFlags_NoResize))
|
||||
@@ -294,8 +339,23 @@ ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector<AudioDevice>& dev
|
||||
ImGui::TableNextColumn();
|
||||
if (dev.state == DEVICE_STATE_ACTIVE)
|
||||
{
|
||||
// Log scale because it looks better (no actual reason for these exact numbers)
|
||||
float meterValue = log10f(getMeterValue(dev.meterInterface) * 9. + 1.);
|
||||
// Mute button
|
||||
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();
|
||||
ImVec2 windowPos = ImGui::GetWindowPos();
|
||||
@@ -306,21 +366,34 @@ ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector<AudioDevice>& dev
|
||||
const float linePaddingX = 3.;
|
||||
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) * 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 prevVolume = volume;
|
||||
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)
|
||||
if (ImGui::SliderFloat("", &volume, 0., 1., "", ImGuiSliderFlags_NoRoundToFormat | ImGuiSliderFlags_AlwaysClamp))
|
||||
{
|
||||
setVolume(dev.volumeInterface, volume);
|
||||
}
|
||||
|
||||
if (isDeviceMuted) ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
// Defaults
|
||||
@@ -331,7 +404,7 @@ ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector<AudioDevice>& dev
|
||||
{
|
||||
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);
|
||||
}
|
||||
@@ -341,7 +414,7 @@ ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector<AudioDevice>& dev
|
||||
{
|
||||
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);
|
||||
}
|
||||
@@ -369,24 +442,3 @@ void drawCircle(float radius, ImU32 color)
|
||||
ImVec2 windowPos = ImGui::GetWindowPos();
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "ImguiBase.h"
|
||||
#include "ApplicationData.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
void init(DrawData& drawData, ApplicationData& customData);
|
||||
void draw(DrawData& drawData, ApplicationData& customData);
|
||||
void cleanup(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);
|
||||
void drawCircle(float radius, ImU32 color);
|
||||
|
||||
LRESULT trayIconEventHandler(int code, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
@@ -71,8 +71,8 @@ IDI_ICON1 ICON "kaiju.ico"
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,1
|
||||
PRODUCTVERSION 1,0,0,1
|
||||
FILEVERSION 1,0,4,1
|
||||
PRODUCTVERSION 1,0,4,1
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
@@ -89,12 +89,12 @@ BEGIN
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Asuro"
|
||||
VALUE "FileDescription", "Audio Thingy"
|
||||
VALUE "FileVersion", "1.0.0.1"
|
||||
VALUE "FileVersion", "1.0.4.1"
|
||||
VALUE "InternalName", "AsuroTool.exe"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2022"
|
||||
VALUE "OriginalFilename", "AsuroTool.exe"
|
||||
VALUE "ProductName", "Audio Thingy"
|
||||
VALUE "ProductVersion", "1.0.0.1"
|
||||
VALUE "ProductVersion", "1.0.4.1"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
@@ -111,7 +111,7 @@ END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_STRING_TOOLTIP "uwu"
|
||||
IDS_STRING_TOOLTIP "Audio Thingy"
|
||||
END
|
||||
|
||||
#endif // English (United Kingdom) resources
|
||||
|
||||
@@ -93,10 +93,14 @@
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<DisableSpecificWarnings>4305; 4244</DisableSpecificWarnings>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<IgnoreSpecificDefaultLibraries>
|
||||
</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@@ -108,12 +112,16 @@
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<DisableSpecificWarnings>4305; 4244</DisableSpecificWarnings>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<IgnoreSpecificDefaultLibraries>
|
||||
</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -123,10 +131,14 @@
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<DisableSpecificWarnings>4305; 4244</DisableSpecificWarnings>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<IgnoreSpecificDefaultLibraries>
|
||||
</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@@ -138,12 +150,16 @@
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<DisableSpecificWarnings>4305; 4244</DisableSpecificWarnings>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>pathcch.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<IgnoreSpecificDefaultLibraries>
|
||||
</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
@@ -152,6 +168,7 @@
|
||||
<ClCompile Include="AudioNotificationListener.cpp" />
|
||||
<ClCompile Include="Settings.cpp" />
|
||||
<ClCompile Include="Util.cpp" />
|
||||
<ClCompile Include="WindowsShell.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ApplicationData.h" />
|
||||
@@ -163,6 +180,7 @@
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="Settings.h" />
|
||||
<ClInclude Include="Util.h" />
|
||||
<ClInclude Include="WindowsShell.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ImguiBase\ImguiBase.vcxproj">
|
||||
|
||||
@@ -39,6 +39,9 @@
|
||||
<ClCompile Include="Settings.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="WindowsShell.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="AsuroTool.h">
|
||||
@@ -65,6 +68,9 @@
|
||||
<ClInclude Include="PolicyConfig.h">
|
||||
<Filter>Header Files\Audio</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WindowsShell.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CopyFileToFolders Include="Montserrat-Regular.ttf">
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
#include "AudioApi.h"
|
||||
#include "Util.h"
|
||||
#include "PolicyConfig.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <functiondiscoverykeys.h>
|
||||
#include <endpointvolume.h>
|
||||
|
||||
#include <initguid.h>
|
||||
#include <mmdeviceapi.h>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "Util.h"
|
||||
#include "AudioApi.h"
|
||||
#include "PolicyConfig.h"
|
||||
#include <iostream>
|
||||
|
||||
void initAudio(ApplicationData& appData)
|
||||
{
|
||||
@@ -31,7 +35,7 @@ void loadAudioDevices(AudioData& audioData, std::vector<AudioDevice>& deviceList
|
||||
deviceList.clear();
|
||||
|
||||
HRESULT err;
|
||||
IMMDeviceCollection* deviceCollection = NULL;
|
||||
IMMDeviceCollection* deviceCollection = nullptr;
|
||||
|
||||
err = audioData.deviceEnumerator->EnumAudioEndpoints(deviceType, DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED, &deviceCollection);
|
||||
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);
|
||||
if (isError(err, "Failed to count audio devices: ")) return;
|
||||
|
||||
IMMDevice* defaultConsoleDevice = NULL;
|
||||
IMMDevice* defaultConsoleDevice = nullptr;
|
||||
LPWSTR defaultConsoleId = nullptr;
|
||||
err = audioData.deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eConsole, &defaultConsoleDevice);
|
||||
if (!FAILED(err))
|
||||
@@ -48,7 +52,7 @@ void loadAudioDevices(AudioData& audioData, std::vector<AudioDevice>& deviceList
|
||||
defaultConsoleDevice->GetId(&defaultConsoleId);
|
||||
}
|
||||
|
||||
IMMDevice* defaultMediaOutput = NULL;
|
||||
IMMDevice* defaultMediaOutput = nullptr;
|
||||
LPWSTR defaultMediaId = nullptr;
|
||||
err = audioData.deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eMultimedia, &defaultMediaOutput);
|
||||
if (!FAILED(err))
|
||||
@@ -56,7 +60,7 @@ void loadAudioDevices(AudioData& audioData, std::vector<AudioDevice>& deviceList
|
||||
defaultMediaOutput->GetId(&defaultMediaId);
|
||||
}
|
||||
|
||||
IMMDevice* defaultCommunicationOutput = NULL;
|
||||
IMMDevice* defaultCommunicationOutput = nullptr;
|
||||
LPWSTR defaultCommunicationId = nullptr;
|
||||
err = audioData.deviceEnumerator->GetDefaultAudioEndpoint(deviceType, ERole::eCommunications, &defaultCommunicationOutput);
|
||||
if (!FAILED(err))
|
||||
@@ -66,57 +70,35 @@ void loadAudioDevices(AudioData& audioData, std::vector<AudioDevice>& deviceList
|
||||
|
||||
for (UINT i = 0; i < deviceCount; i += 1)
|
||||
{
|
||||
AudioDevice deviceData{};
|
||||
|
||||
err = deviceCollection->Item(i, &deviceData.device);
|
||||
IMMDevice* device;
|
||||
err = deviceCollection->Item(i, &device);
|
||||
if (isError(err, std::stringstream("Failed to get device ") << i << ": "))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
LPWSTR deviceId;
|
||||
err = deviceData.device->GetId(&deviceId);
|
||||
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)
|
||||
err = device->GetId(&deviceId);
|
||||
if (!isError(err, std::stringstream("Failed to get device id ") << i << ": "))
|
||||
{
|
||||
deviceData.isDefaultConsole = wcscmp(defaultConsoleId, deviceId) == 0;
|
||||
}
|
||||
if (defaultMediaId)
|
||||
{
|
||||
deviceData.isDefaultMedia = wcscmp(defaultMediaId, deviceId) == 0;
|
||||
}
|
||||
if (defaultCommunicationId)
|
||||
{
|
||||
deviceData.isDefaultCommunication = wcscmp(defaultCommunicationId, deviceId) == 0;
|
||||
AudioDevice audioDevice(device, deviceId);
|
||||
|
||||
if (defaultConsoleId)
|
||||
{
|
||||
audioDevice.isDefaultConsole = wcscmp(defaultConsoleId, deviceId) == 0;
|
||||
}
|
||||
if (defaultMediaId)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -150,7 +132,7 @@ HRESULT getDevicePropertyString(IPropertyStore* propertyStore, const PROPERTYKEY
|
||||
|
||||
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);
|
||||
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: ");
|
||||
}
|
||||
|
||||
float getMeterValue(IAudioMeterInformation* meterInterface)
|
||||
UINT getMeterValues(IAudioMeterInformation* meterInterface, std::array<float, 2>& outLevels)
|
||||
{
|
||||
float volume;
|
||||
if (FAILED(meterInterface->GetPeakValue(&volume)))
|
||||
{
|
||||
volume = 0.;
|
||||
}
|
||||
UINT channelCount;
|
||||
if (FAILED(meterInterface->GetMeteringChannelCount(&channelCount)) || channelCount > 2) return 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <mmdeviceapi.h>
|
||||
|
||||
#include "ApplicationData.h"
|
||||
|
||||
enum class AudioProcessingState
|
||||
{
|
||||
Enabled,
|
||||
Disabled,
|
||||
Unknown
|
||||
};
|
||||
|
||||
void initAudio(ApplicationData& appData);
|
||||
void loadAudioDevices(AudioData& audioData, std::vector<AudioDevice>& deviceList, EDataFlow deviceType);
|
||||
void reloadDeviceLists(AudioData& audioData);
|
||||
@@ -14,4 +19,9 @@ void setDefaultAudioDevice(AudioData& audioData, const wchar_t* deviceId, ERole
|
||||
|
||||
float getVolume(IAudioEndpointVolume* volumeInterface);
|
||||
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);
|
||||
|
||||
@@ -34,7 +34,25 @@ HRESULT __stdcall AudioNotificationListener::OnDeviceAdded(LPCWSTR pwstrDeviceId
|
||||
HRESULT result = audioData->deviceEnumerator->GetDevice(pwstrDeviceId, &newDevice);
|
||||
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;
|
||||
@@ -50,7 +68,9 @@ HRESULT __stdcall AudioNotificationListener::OnDeviceRemoved(LPCWSTR pwstrDevice
|
||||
if (wcscmp(deviceListIterator->id.c_str(), pwstrDeviceId) == 0)
|
||||
{
|
||||
deviceListIterator = deviceList.erase(deviceListIterator);
|
||||
continue;
|
||||
}
|
||||
deviceListIterator++;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -126,7 +146,7 @@ HRESULT __stdcall AudioNotificationListener::QueryInterface(REFIID riid, void**
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppvObject = NULL;
|
||||
*ppvObject = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <initguid.h>
|
||||
#include <mmdeviceapi.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class AudioData;
|
||||
class ApplicationData;
|
||||
class AudioNotificationListener : public IMMNotificationClient {
|
||||
|
||||
@@ -115,6 +115,9 @@ public:
|
||||
PCWSTR,
|
||||
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;
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "Util.h"
|
||||
#include "Settings.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
extern bool justDocked;
|
||||
extern DrawData* gDrawData;
|
||||
extern ApplicationData* gAppData;
|
||||
@@ -10,8 +12,8 @@ extern ApplicationData* gAppData;
|
||||
void initSettings(DrawData& drawData, ApplicationData& appData)
|
||||
{
|
||||
ImGuiSettingsHandler ini_handler;
|
||||
ini_handler.TypeName = "ApplicationSettings";
|
||||
ini_handler.TypeHash = ImHashStr("ApplicationSettings");
|
||||
ini_handler.TypeName = APPLICATION_SETTINGS_GROUP;
|
||||
ini_handler.TypeHash = ImHashStr(APPLICATION_SETTINGS_GROUP);
|
||||
ini_handler.ReadOpenFn = settingsReadOpen;
|
||||
ini_handler.ReadLineFn = settingsReadLine;
|
||||
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)
|
||||
{
|
||||
if (strlen(line) == 0) return;
|
||||
|
||||
ApplicationSettings* settings = (ApplicationSettings*)entry;
|
||||
|
||||
int docked;
|
||||
@@ -36,19 +40,54 @@ void settingsReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* en
|
||||
{
|
||||
settings->docked = (bool)docked;
|
||||
}
|
||||
|
||||
int autostart;
|
||||
if (sscanf_s(line, "autostart=%i", &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)
|
||||
{
|
||||
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("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)
|
||||
@@ -74,19 +113,16 @@ void setAutostart(bool newValue)
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
HKEY runKey = NULL;
|
||||
HKEY runKey = nullptr;
|
||||
hr = RegCreateKey(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", &runKey);
|
||||
if (isError(hr, "Failed to find/create autostart run key: ")) return;
|
||||
|
||||
if (newValue)
|
||||
{
|
||||
std::wstring appPath;
|
||||
appPath.resize(MAX_PATH_LENGTH);
|
||||
hr = GetModuleFileName(NULL, &appPath[0], static_cast<DWORD>(appPath.size()));
|
||||
if (isError(hr, "Failed to get executable name: ")) return;
|
||||
appPath.resize(wcslen(appPath.data()));
|
||||
if (FAILED(getAppPath(appPath))) return;
|
||||
|
||||
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;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#pragma once
|
||||
#include "ApplicationData.h"
|
||||
#include "ImguiBase.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);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "Util.h"
|
||||
#include "pathcch.h"
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
bool isError(const HRESULT result, const std::stringstream message);
|
||||
bool isError(const HRESULT result, const char* message);
|
||||
std::string utf8Encode(const std::wstring& wstr);
|
||||
HRESULT getAppPath(std::wstring& outPath);
|
||||
HRESULT getAppDir(std::wstring& outPath);
|
||||
|
||||
102
AsuroTool/WindowsShell.cpp
Normal file
102
AsuroTool/WindowsShell.cpp
Normal 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
8
AsuroTool/WindowsShell.h
Normal 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);
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "imgui.h"
|
||||
#include "remixicon.h"
|
||||
|
||||
class DrawData {
|
||||
public:
|
||||
|
||||
@@ -107,6 +107,8 @@
|
||||
<Lib>
|
||||
<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>
|
||||
<IgnoreSpecificDefaultLibraries>
|
||||
</IgnoreSpecificDefaultLibraries>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@@ -130,6 +132,8 @@
|
||||
<Lib>
|
||||
<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>
|
||||
<IgnoreSpecificDefaultLibraries>
|
||||
</IgnoreSpecificDefaultLibraries>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -149,6 +153,8 @@
|
||||
<Lib>
|
||||
<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>
|
||||
<IgnoreSpecificDefaultLibraries>
|
||||
</IgnoreSpecificDefaultLibraries>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@@ -172,6 +178,8 @@
|
||||
<Lib>
|
||||
<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>
|
||||
<IgnoreSpecificDefaultLibraries>
|
||||
</IgnoreSpecificDefaultLibraries>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
@@ -194,6 +202,7 @@
|
||||
<ClInclude Include="imgui\headers\imstb_rectpack.h" />
|
||||
<ClInclude Include="imgui\headers\imstb_textedit.h" />
|
||||
<ClInclude Include="imgui\headers\imstb_truetype.h" />
|
||||
<ClInclude Include="remixicon.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Font Include="Montserrat-Regular.ttf" />
|
||||
|
||||
@@ -74,6 +74,9 @@
|
||||
<ClInclude Include="ImguiBase.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="remixicon.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Font Include="Montserrat-Regular.ttf">
|
||||
|
||||
2273
ImguiBase/remixicon.h
Normal file
2273
ImguiBase/remixicon.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -96,6 +96,8 @@
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<IgnoreSpecificDefaultLibraries>
|
||||
</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@@ -112,6 +114,8 @@
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<IgnoreSpecificDefaultLibraries>
|
||||
</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@@ -124,6 +128,8 @@
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<IgnoreSpecificDefaultLibraries>
|
||||
</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
@@ -140,6 +146,8 @@
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<IgnoreSpecificDefaultLibraries>
|
||||
</IgnoreSpecificDefaultLibraries>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user