20111013

Making my Comp Shut Up

For some reason the keyboard filter driver that comes with my new Asus netbook doesn't work properly. Only some of the special function keys actually work. The most important one that doesn't work is the mute toggle. Instead it just, well, does nothing. This is pretty annoying, so I wanted to get the functionality back.

So I set out to write a program to toggle the mute of my netbook. Turns out not too many people have done this properly on Windows 7 or Vista. I found one CodeProject program to control audio, but it was written in managed code, and I needed to register to download it.

Look at me: I'd rather re-implement something like this than register for a site to download the already-done work. I don't know if that's good or not.

Anyway, that guy was on the right track. You use the new MMDevice APIs to do everything. Here's the code, for people's reference.

And link against mmdevapi.lib.

#define UNICODE 1
#include <windows.h>
#include <atlbase.h>
#include <stdio.h>
#include <stdlib.h>

#include <mmdeviceapi.h>
#include <endpointvolume.h>

using namespace std;

HRESULT ToggleMute();
void Usage();

const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);

int __cdecl wmain(int argc, wchar_t* argv[])
{
    HRESULT hr = S_OK;

    CoInitialize(NULL);

    if (argc > 1)
    {
        if (_wcsicmp(argv[1], L"/togglemute") == 0)
        {
            hr = ToggleMute();
            return hr;
        }
    }

    Usage();
    hr = E_INVALIDARG;

    return hr;
}

HRESULT ToggleMute()
{
    HRESULT hr = S_OK;

    CComPtr<IMMDeviceEnumerator> spDeviceEnum;
    hr = spDeviceEnum.CoCreateInstance(CLSID_MMDeviceEnumerator);

    if (spDeviceEnum)
    {
        CComPtr<IMMDevice> spDevice;
        hr = spDeviceEnum->GetDefaultAudioEndpoint(eRender, eMultimedia, &spDevice);

        if (spDevice)
        {
            CComPtr<IAudioEndpointVolume> spVolume;
            hr = spDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, reinterpret_cast<void**>(&spVolume));

            if (spVolume)
            {
                BOOL fMuted = FALSE;
                hr = spVolume->GetMute(&fMuted);

                if (FAILED(hr))
                {
                    wprintf(L"failed GetMute: %08LX\n", hr);
                    fMuted = FALSE;
                    // but keep going; mute the system, the safer thing to do
                }

                wprintf(L"%smuting\n", (fMuted ? L"un" : L""));

                hr = spVolume->SetMute(!fMuted, NULL);

                if (FAILED(hr))
                {
                    wprintf(L"failed SetMute: %08LX\n", hr);
                }
            }
            else
            {
                wprintf(L"failed Activate endpoint volume: %08LX\n", hr);
            }
        }
        else
        {
            wprintf(L"failed GetDefaultAudioEndpoint: %08LX\n", hr);
        }
    }
    else
    {
        wprintf(L"failed CoCreate: %08LX\n", hr);
    }

    return hr;
}

void Usage()
{
    wprintf(L"Usage: soundtool.exe [/ToggleMute]\n");
}

And then I teamed this up with the magical AutoHotKey to make the scenario transparent.

^!F10::Run, F:\bin\soundtool.exe /ToggleMute, , Hide

0 comments:

Post a Comment