commit ea3fc2fa51f5792987e12daa85768904f2cde62a Author: unknown Date: Sun Jul 18 14:15:11 2021 -0400 import diff --git a/ShitMuter.sln b/ShitMuter.sln new file mode 100644 index 0000000..7796777 --- /dev/null +++ b/ShitMuter.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ShitMuter", "ShitMuter\ShitMuter.vcxproj", "{F8B9EAD5-19B7-43EA-81FA-897B144BAB22}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F8B9EAD5-19B7-43EA-81FA-897B144BAB22}.Debug|Win32.ActiveCfg = Debug|Win32 + {F8B9EAD5-19B7-43EA-81FA-897B144BAB22}.Debug|Win32.Build.0 = Debug|Win32 + {F8B9EAD5-19B7-43EA-81FA-897B144BAB22}.Release|Win32.ActiveCfg = Release|Win32 + {F8B9EAD5-19B7-43EA-81FA-897B144BAB22}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/ShitMuter/Resource.aps b/ShitMuter/Resource.aps new file mode 100644 index 0000000..85c3b39 Binary files /dev/null and b/ShitMuter/Resource.aps differ diff --git a/ShitMuter/Resource.rc b/ShitMuter/Resource.rc new file mode 100644 index 0000000..e4c7438 Binary files /dev/null and b/ShitMuter/Resource.rc differ diff --git a/ShitMuter/ShitMuter.vcxproj b/ShitMuter/ShitMuter.vcxproj new file mode 100644 index 0000000..8e33930 --- /dev/null +++ b/ShitMuter/ShitMuter.vcxproj @@ -0,0 +1,102 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {F8B9EAD5-19B7-43EA-81FA-897B144BAB22} + Win32Proj + ShitMuter + 10.0 + + + + Application + true + v142 + MultiByte + + + Application + false + v142 + true + MultiByte + + + + + + + + + + + + + true + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + false + + + Windows + true + shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + stdcpp17 + + + Windows + true + true + true + shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + + + PerMonitorHighDPIAware + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ShitMuter/ShitMuter.vcxproj.filters b/ShitMuter/ShitMuter.vcxproj.filters new file mode 100644 index 0000000..3155ce1 --- /dev/null +++ b/ShitMuter/ShitMuter.vcxproj.filters @@ -0,0 +1,40 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + Resource Files + + + Resource Files + + + + + Header Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/ShitMuter/ShitMuter.vcxproj.user b/ShitMuter/ShitMuter.vcxproj.user new file mode 100644 index 0000000..a375ae3 --- /dev/null +++ b/ShitMuter/ShitMuter.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/ShitMuter/Source.cpp b/ShitMuter/Source.cpp new file mode 100644 index 0000000..eb0d475 --- /dev/null +++ b/ShitMuter/Source.cpp @@ -0,0 +1,532 @@ +#include +#include +#include +#include +#include +#include "resource.h" +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define WM_TRAY_MENU (WM_USER) +#define WM_DIE (WM_USER+1) +#define WM_CFG (WM_USER+2) + +HWND win; +NOTIFYICONDATA icondat; +UINT wmTaskbarCreated = 0; +HWINEVENTHOOK hook; +HWINEVENTHOOK hook2; + +// can we register to handle new streams? new devices, new sessions + +//----------------------------------------------------------- +// Example implementation of IMMNotificationClient interface. +// When the status of audio endpoint devices change, the +// MMDevice module calls these methods to notify the client. +//----------------------------------------------------------- + +#define SAFE_RELEASE(punk) \ + if ((punk) != NULL) \ + { (punk)->Release(); (punk) = NULL; } + +class DeviceNotification : public IMMNotificationClient +{ + LONG _cRef; + std::function _addCallback; + +public: + DeviceNotification(std::function callback) : + _addCallback(std::move(callback)), + _cRef(1) + { + } + + ~DeviceNotification() + { + } + + // IUnknown methods -- AddRef, Release, and QueryInterface + + ULONG STDMETHODCALLTYPE AddRef() + { + return InterlockedIncrement(&_cRef); + } + + ULONG STDMETHODCALLTYPE Release() + { + ULONG ulRef = InterlockedDecrement(&_cRef); + if (0 == ulRef) + { + delete this; + } + return ulRef; + } + + HRESULT STDMETHODCALLTYPE QueryInterface( + REFIID riid, VOID** ppvInterface) + { + if (IID_IUnknown == riid) + { + AddRef(); + *ppvInterface = (IUnknown*)this; + } + else if (__uuidof(IMMNotificationClient) == riid) + { + AddRef(); + *ppvInterface = (IMMNotificationClient*)this; + } + else + { + *ppvInterface = NULL; + return E_NOINTERFACE; + } + return S_OK; + } + + // Callback methods for device-event notifications. + + HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged( + EDataFlow flow, ERole role, + LPCWSTR pwstrDeviceId) + { + return S_OK; + } + + HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId) + { + _addCallback(pwstrDeviceId); + return S_OK; + }; + + HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId) + { + return S_OK; + } + + HRESULT STDMETHODCALLTYPE OnDeviceStateChanged( + LPCWSTR pwstrDeviceId, + DWORD dwNewState) + { + return S_OK; + } + + HRESULT STDMETHODCALLTYPE OnPropertyValueChanged( + LPCWSTR pwstrDeviceId, + const PROPERTYKEY key) + { + return S_OK; + } +}; + +class SessionNotification : public IAudioSessionNotification +{ +private: + LONG _ref; + std::function _addCallback; +public: + ~SessionNotification() {}; + SessionNotification(std::function callback) : _addCallback(std::move(callback)), _ref(1) {} + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv) + { + if (IID_IUnknown == riid) + { + AddRef(); + *ppv = (IUnknown*)this; + } + else if (__uuidof(IAudioSessionNotification) == riid) + { + AddRef(); + *ppv = (IAudioSessionNotification*)this; + } + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + return S_OK; + } + + ULONG STDMETHODCALLTYPE AddRef() + { + return InterlockedIncrement(&_ref); + } + + ULONG STDMETHODCALLTYPE Release() + { + ULONG ulRef = InterlockedDecrement(&_ref); + if (0 == ulRef) + { + delete this; + } + return ulRef; + } + + HRESULT STDMETHODCALLTYPE OnSessionCreated(IAudioSessionControl* pNewSession) + { + _addCallback(); + return S_OK; + } +}; + +std::set appsToMute; + +std::set loadSettingsFile(std::string settingsFilename) +{ + std::set appLines; + std::ifstream in(settingsFilename); + std::string line; + while (!in.eof() && !in.bad() && in.is_open()) { + getline(in, line); + if (!line.empty()) + appLines.insert(line); + } + return appLines; +} + +void saveSettingsFile(std::string settingsFilename, std::set appLines) +{ + std::ofstream out(settingsFilename); + for (std::string line : appLines) { + out << line << std::endl; + } +} + + +std::vector CreateSessionManagers() +{ + std::vector sessionManagers; + HRESULT hr = S_OK; + + IMMDeviceEnumerator* pEnumerator = NULL; + IMMDeviceCollection* pDeviceCollection = NULL; + + // Create the device enumerator. + hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator); + pEnumerator->EnumAudioEndpoints(EDataFlow::eRender, DEVICE_STATE_ACTIVE, &pDeviceCollection); + UINT cDevices; + pDeviceCollection->GetCount(&cDevices); + for (UINT i = 0; i < cDevices; i++) { + IMMDevice* pDevice = NULL; + IAudioSessionManager2* pSessionManager = NULL; + pDeviceCollection->Item(i, &pDevice); + hr = pDevice->Activate(__uuidof(IAudioSessionManager2), CLSCTX_ALL, NULL, (void**)&pSessionManager); + sessionManagers.push_back(pSessionManager); + pDevice->Release(); + } + + // Return the pointer to the caller. + pDeviceCollection->Release(); + pEnumerator->Release(); + return sessionManagers; +} + +std::string pidToFilename(DWORD pid) { + DWORD maxLength = MAX_PATH; + char moduleFileName[MAX_PATH] = { 0 }; + HANDLE process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); + QueryFullProcessImageName(process, 0, moduleFileName, &maxLength); + CloseHandle(process); + PathStripPath(moduleFileName); + return std::string(moduleFileName); +} + + +auto muteAllAction = [](std::string checkFilename) { return true; }; +auto unmuteAllAction = [](std::string checkFilename) { return false; }; +auto muteAllExcept(std::string filename) +{ + return [filename](std::string checkFilename) + { + return filename != checkFilename; + }; +} +std::function lastAction = muteAllAction; + +void PerformMuteAction(std::function mutePicker) { + lastAction = mutePicker; + for (IAudioSessionManager2* sessionManager : CreateSessionManagers()) { + IAudioSessionEnumerator* enumerator; + int sessionCount = 0; + sessionManager->GetSessionEnumerator(&enumerator); + enumerator->GetCount(&sessionCount); + for (int i = 0; i < sessionCount; i++) + { + IAudioSessionControl* control; + IAudioSessionControl2* control2; + ISimpleAudioVolume* vol; + enumerator->GetSession(i, &control); + control->QueryInterface(&control2); + control2->QueryInterface(&vol); + DWORD pid; + control2->GetProcessId(&pid); + + std::string filename = pidToFilename(pid); + if (appsToMute.find(filename) != appsToMute.end()) + { + bool muted = mutePicker(filename); + vol->SetMute(muted, NULL); + } + control2->Release(); + control->Release(); + vol->Release(); + } + enumerator->Release(); + sessionManager->Release(); + } +} + + +void CALLBACK winEventProc(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime) +{ + if (event == EVENT_SYSTEM_FOREGROUND || event == EVENT_SYSTEM_MINIMIZEEND) + { + DWORD pid; + GetWindowThreadProcessId(hwnd, &pid); + std::string filename = pidToFilename(pid); + + if (appsToMute.find(filename) != appsToMute.end()) + { + PerformMuteAction(muteAllExcept(filename)); + icondat.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1)); + Shell_NotifyIcon(NIM_MODIFY, &icondat); + DestroyIcon(icondat.hIcon); + } else { + PerformMuteAction(muteAllAction); + icondat.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON2)); + Shell_NotifyIcon(NIM_MODIFY, &icondat); + DestroyIcon(icondat.hIcon); + } + } +} + +BOOL CALLBACK CfgDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + for (std::string exe : appsToMute) { + SendDlgItemMessage(hwnd, IDC_EXELIST, LB_ADDSTRING, 0, (LPARAM)exe.c_str()); + } + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_ADDBUTTON: + { + int len = GetWindowTextLength(GetDlgItem(hwnd, IDC_EXEEDIT)) + 1; + auto str = std::make_unique(len); + GetDlgItemText(hwnd, IDC_EXEEDIT, str.get(), len); + SendDlgItemMessage(hwnd, IDC_EXELIST, LB_ADDSTRING, 0, (LPARAM)str.get()); + SetDlgItemText(hwnd, IDC_EXEEDIT, ""); + } + break; + case IDC_DELBUTTON: + { + LRESULT index = SendDlgItemMessage(hwnd, IDC_EXELIST, LB_GETCURSEL, NULL, NULL); + SendDlgItemMessage(hwnd, IDC_EXELIST, LB_DELETESTRING, index, NULL); + } + break; + case IDOK: + { + LRESULT count = SendDlgItemMessage(hwnd, IDC_EXELIST, LB_GETCOUNT, NULL, NULL); + appsToMute.clear(); + for (int i = 0; i < count; i++) { + unsigned int length = SendDlgItemMessage(hwnd, IDC_EXELIST, LB_GETTEXTLEN, i, NULL) + 1; + auto exeLineChars = std::make_unique(length); + SendDlgItemMessage(hwnd, IDC_EXELIST, LB_GETTEXT, i, (LPARAM)exeLineChars.get()); + std::string exeLine(exeLineChars.get()); + appsToMute.insert(exeLine); + } + saveSettingsFile("mute.txt", appsToMute); + EndDialog(hwnd, IDOK); + } + break; + case IDCANCEL: + EndDialog(hwnd, IDCANCEL); + break; + } + break; + default: + return FALSE; + } + return TRUE; +} + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + if (message == wmTaskbarCreated) { + Shell_NotifyIcon(NIM_ADD, &icondat); + return 0; + } + + switch (message) + { + case WM_CREATE: + memset(&icondat, 0, sizeof(icondat)); + icondat.cbSize = sizeof(icondat); + icondat.hWnd = hWnd; + icondat.uID = 1; + icondat.uFlags = NIF_ICON | NIF_MESSAGE; + icondat.uCallbackMessage = WM_TRAY_MENU; + icondat.uVersion = NOTIFYICON_VERSION; + icondat.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1)); + Shell_NotifyIcon(NIM_ADD, &icondat); + DestroyIcon(icondat.hIcon); + break; + case WM_TRAY_MENU: + if (lParam == WM_RBUTTONDOWN) { + POINT pt; + GetCursorPos(&pt); + HMENU menu = CreatePopupMenu(); + InsertMenu(menu, -1, MF_BYPOSITION, WM_CFG, "Configure..."); + InsertMenu(menu, -1, MF_SEPARATOR | MF_BYPOSITION, 0, NULL); + InsertMenu(menu, -1, MF_BYPOSITION, WM_DIE, "Exit"); + SetForegroundWindow(hWnd); + TrackPopupMenu(menu, TPM_BOTTOMALIGN, + pt.x, pt.y, 0, hWnd, NULL); + DestroyMenu(menu); + } + break; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case WM_DIE: + PerformMuteAction(unmuteAllAction); + Shell_NotifyIcon(NIM_DELETE, &icondat); + UnhookWinEvent(hook); + UnhookWinEvent(hook2); + saveSettingsFile("mute.txt", appsToMute); + ExitProcess(0); + break; + case WM_CFG: + DialogBox(NULL, MAKEINTRESOURCE(IDD_CFGDIALOG), hWnd, CfgDlgProc); + break; + } + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + + +class AudFucker +{ + DeviceNotification* _endpointNotificationClient; + SessionNotification* _sessionNotification; + IMMDeviceEnumerator* _enumerator = NULL; + std::vector _knownSessions; +public: + AudFucker() + { + _endpointNotificationClient = new DeviceNotification( + [this](LPCWSTR pwstrDeviceId) { + IMMDevice* pDevice = NULL; + _enumerator->GetDevice(pwstrDeviceId, &pDevice); + if (pDevice != NULL) + fuckulateDevice(pDevice); + OutputDebugString("Device added\n"); + PerformMuteAction(lastAction); + } + ); + _sessionNotification = new SessionNotification( + []() { + OutputDebugString("Session added\n"); + PerformMuteAction(lastAction); + } + ); + CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&_enumerator); + int reval = _enumerator->RegisterEndpointNotificationCallback(_endpointNotificationClient); + hookExistingDevices(); + } + + ~AudFucker() { + _enumerator->UnregisterEndpointNotificationCallback(_endpointNotificationClient); + for (IAudioSessionManager2* session : _knownSessions) { + session->UnregisterSessionNotification(_sessionNotification); + session->Release(); + } + _sessionNotification->Release(); + _endpointNotificationClient->Release(); + } + void fuckulateDevice(IMMDevice* device) + { + IAudioSessionManager2* pSessionManager = NULL; + device->Activate(__uuidof(IAudioSessionManager2), CLSCTX_ALL, NULL, (void**)&pSessionManager); + pSessionManager->RegisterSessionNotification(_sessionNotification); + _knownSessions.push_back(pSessionManager); + IAudioSessionEnumerator* enumerator; + // HACK: we must discard a session enumerator in order to enable the session notification. + // In a better version of this application we'd probably try to collect all known sessions and update them all without the need to rescan everything + pSessionManager->GetSessionEnumerator(&enumerator); + enumerator->Release(); + } + + void hookExistingDevices() { + + + IMMDeviceCollection* pDeviceCollection = NULL; + + // Create the device enumerator. + _enumerator->EnumAudioEndpoints(EDataFlow::eRender, DEVICE_STATE_ACTIVE, &pDeviceCollection); + UINT cDevices; + pDeviceCollection->GetCount(&cDevices); + for (UINT i = 0; i < cDevices; i++) { + IMMDevice* pDevice = NULL; + pDeviceCollection->Item(i, &pDevice); + fuckulateDevice(pDevice); + pDevice->Release(); + } + pDeviceCollection->Release(); + } +}; + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR lpCmdLine, int nCmdShow) +{ + CoInitialize(NULL); + + + appsToMute = loadSettingsFile("mute.txt"); + wmTaskbarCreated = RegisterWindowMessage("TaskbarCreated"); + + hook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, NULL, winEventProc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); + hook2 = SetWinEventHook(EVENT_SYSTEM_MINIMIZEEND, EVENT_SYSTEM_MINIMIZEEND, NULL, winEventProc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); + if (hook == 0) + { + MessageBox(0, "Failed to setwineventhook", "Fuck", 0); + return 0; + } + + WNDCLASS wc; + memset(&wc, 0, sizeof(wc)); + wc.lpfnWndProc = WndProc; + wc.hInstance = hInstance; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wc.lpszClassName = "sysTrayTest"; + RegisterClass(&wc); + + win = CreateWindow("sysTrayTest", "You can't see this.", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, 50, 50, NULL, NULL, hInstance, NULL); + + + AudFucker myFucker; + + MSG msg; + while(GetMessage(&msg, NULL, 0, 0) > 0) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return 0; +} \ No newline at end of file diff --git a/ShitMuter/icon1.ico b/ShitMuter/icon1.ico new file mode 100644 index 0000000..9885bc2 Binary files /dev/null and b/ShitMuter/icon1.ico differ diff --git a/ShitMuter/icon2.ico b/ShitMuter/icon2.ico new file mode 100644 index 0000000..e864473 Binary files /dev/null and b/ShitMuter/icon2.ico differ diff --git a/ShitMuter/mute.txt b/ShitMuter/mute.txt new file mode 100644 index 0000000..edacd5f --- /dev/null +++ b/ShitMuter/mute.txt @@ -0,0 +1 @@ +Cemu.exe diff --git a/ShitMuter/resource.h b/ShitMuter/resource.h new file mode 100644 index 0000000..48f9d65 Binary files /dev/null and b/ShitMuter/resource.h differ