#include #include #include #include #include #include #include #include void CALLBACK MidiInProc(HMIDIIN, UINT, DWORD, DWORD, DWORD); void ChangeVolume(double); void HttpPut(wchar_t*, wchar_t*, LPSTR); void KeyboardPress(int); void AugustLock(int); void UpdateIcon(int, int, int); DWORD WINAPI resetIcon(void*); int knobsVal[8]; NOTIFYICONDATA notifyIcon; HWND hWnd; ULONG_PTR gdiplusToken; HICON hIcon; clock_t time1; bool windowVisibility = false; bool needResetIcon = false; void main(void) { MIDIINCAPS midiInCap; HMIDIIN inHandle; int numOfDevs; Gdiplus::GdiplusStartupInput gdiplusStartupInput; Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); hWnd = FindWindow(L"ConsoleWindowClass", NULL); ShowWindow(hWnd, windowVisibility); notifyIcon.cbSize = sizeof(notifyIcon); notifyIcon.hWnd = hWnd; wcscpy_s(notifyIcon.szTip, L"MIDI Control"); notifyIcon.uCallbackMessage = WM_LBUTTONDOWN; notifyIcon.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE; notifyIcon.uID = 1; Shell_NotifyIcon(NIM_ADD, ¬ifyIcon); for (int i = 0; i < 8; i++) knobsVal[i] = -1; numOfDevs = midiInGetNumDevs(); for (int i = 0; i < numOfDevs; i++) if (!midiInGetDevCaps(i, &midiInCap, sizeof(MIDIINCAPS))) wprintf(L"Device ID #%u: %s\n", i, midiInCap.szPname); if (midiInOpen(&inHandle, 0, (DWORD_PTR)MidiInProc, 0, CALLBACK_FUNCTION)) printf("Err Opening MIDI Device\n"); midiInStart(inHandle); UpdateIcon(-1, 1, 1); while (_getch() != VK_ESCAPE); Shell_NotifyIcon(NIM_DELETE, ¬ifyIcon); midiInStop(inHandle); midiInClose(inHandle); } DWORD WINAPI resetIcon(void* data) { time1 = clock(); if (!needResetIcon) { needResetIcon = true; while (clock() - time1 < 1000); UpdateIcon(-1, 1, 1); needResetIcon = false; } return 0; } void UpdateIcon(int type, int num, int value) { wchar_t tmp[50]; wchar_t types[10] = L"✸⬔"; Gdiplus::Bitmap bitmapText(256, 256); Gdiplus::Graphics g(&bitmapText); g.Clear(Gdiplus::Color(0, 0, 0, 0)); if (type == -1) { Gdiplus::Font font1(L"Arial Black", 96); Gdiplus::PointF origin1(-32, -32); Gdiplus::SolidBrush brush1(Gdiplus::Color(0xFFe6b2c6)); swprintf(tmp, 50, L"MI"); g.DrawString(tmp, wcslen(tmp), &font1, origin1, &brush1); Gdiplus::Font font2(L"Arial Black", 96); Gdiplus::PointF origin2(32, 96); Gdiplus::SolidBrush brush2(Gdiplus::Color(0xFFfef6fb)); swprintf(tmp, 50, L"DI"); g.DrawString(tmp, wcslen(tmp), &font2, origin2, &brush2); } else { // Icon Gdiplus::Font font1(L"Arial Black", 88); Gdiplus::PointF origin1(-36, -32); Gdiplus::SolidBrush brush1(Gdiplus::Color(0xFFfef6fb)); swprintf(tmp, 50, L"%c", types[type]); g.DrawString(tmp, wcslen(tmp), &font1, origin1, &brush1); // num Gdiplus::Font font2(L"Arial Black", 88); Gdiplus::PointF origin2(70, -32); Gdiplus::SolidBrush brush2(Gdiplus::Color(0xFFfef6fb)); swprintf(tmp, 50, L"%X", num); g.DrawString(tmp, wcslen(tmp), &font2, origin2, &brush2); // value Gdiplus::Font font3(L"Arial Black", 100); Gdiplus::PointF origin3(-32, 96); Gdiplus::SolidBrush brush3(Gdiplus::Color(0xFFe6b2c6)); swprintf(tmp, 50, L"%d", value); g.DrawString(tmp, wcslen(tmp), &font3, origin3, &brush3); CreateThread(NULL, 0, resetIcon, NULL, 0, NULL); } bitmapText.GetHICON(¬ifyIcon.hIcon); Shell_NotifyIcon(NIM_MODIFY, ¬ifyIcon); } void CALLBACK MidiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { switch (wMsg) { case MIM_DATA: printf("wMsg=MIM_DATA, dwInstance=%08x, dwParam1=%08x, dwParam2=%08x\n", dwInstance, dwParam1, dwParam2); char buffer[50]; /* Knobs */ if (!(dwParam1 & 0xFF ^ 0xB0)) { UpdateIcon(0, dwParam1 >> 8 & 0xFF, dwParam1 >> 16 & 0xFF); /* Knob 1: PC Volume */ if (!(dwParam1 >> 8 & 0xFF ^ 0x01)) { ChangeVolume((double)(dwParam1 >> 16 & 0xFF) / 127); /* Knob 2: Bedroom Lights & Lightstrip Brightness */ } else if (!(dwParam1 >> 8 & 0xFF ^ 0x02)) { snprintf(buffer, 50, "{\"on\": %s, \"bri\": %d}", (dwParam1 >> 16 & 0xFF) ? "true" : "false", (dwParam1 >> 16 & 0xFF) * 2); if (!((dwParam1 >> 16 & 0xFF) % 8)) HttpPut((wchar_t*)L"censored.localhost", (wchar_t*)L"/api/censored/groups/2/action", (LPSTR)buffer); /* Knob 3: Bedroom Lights & Lightstrip Hue */ } else if (!(dwParam1 >> 8 & 0xFF ^ 0x03)) { snprintf(buffer, 50, "{\"on\": true, \"hue\": %d}", (dwParam1 >> 16 & 0xFF) * 516); if (!((dwParam1 >> 16 & 0xFF) % 8)) HttpPut((wchar_t*)L"censored.localhost", (wchar_t*)L"/api/censored/groups/2/action", (LPSTR)buffer); /* Knob 4: Bedroom Lights & Lightstrip Saturation */ } else if (!(dwParam1 >> 8 & 0xFF ^ 0x04)) { snprintf(buffer, 50, "{\"on\": true, \"sat\": %d}", (dwParam1 >> 16 & 0xFF) * 2); if (!((dwParam1 >> 16 & 0xFF) % 8)) HttpPut((wchar_t*)L"censored.localhost", (wchar_t*)L"/api/censored/groups/2/action", (LPSTR)buffer); /* Knob 5: Press Z - Video Rewind */ } else if (!(dwParam1 >> 8 & 0xFF ^ 0x05)) { if (knobsVal[4] != -1 && knobsVal[4] > dwParam1 >> 16 & 0xFF) KeyboardPress(0x5A); knobsVal[4] = dwParam1 >> 16 & 0xFF; /* Knob 6: Press X - Video Advance */ } else if (!(dwParam1 >> 8 & 0xFF ^ 0x06)) { if (knobsVal[5] != -1 && knobsVal[5] < dwParam1 >> 16 & 0xFF) KeyboardPress(0x58); knobsVal[5] = dwParam1 >> 16 & 0xFF; } /* Pads & Keys */ } else if (!(dwParam1 & 0xFF ^ 0x90)) { UpdateIcon(1, dwParam1 >> 8 & 0xFF, dwParam1 >> 16 & 0xFF); /* Bedroom Light Switch */ if (!(dwParam1 >> 8 & 0xFF ^ 0x30)) { if ((dwParam1 >> 16 & 0xFF) != 0x00) { // ignore key off msg snprintf(buffer, 50, "{\"on\": %s}", ((dwParam1 >> 16 & 0xFF) > 0x10) ? "true" : "false"); // fast press = on, slow press = off HttpPut((wchar_t*)L"censored.localhost", (wchar_t*)L"/api/censored/groups/1/action", (LPSTR)buffer); } /* Light Strip Switch */ } else if (!(dwParam1 >> 8 & 0xFF ^ 0x32)) { if ((dwParam1 >> 16 & 0xFF) != 0x00) { // ignore key off msg snprintf(buffer, 50, "{\"on\": %s}", ((dwParam1 >> 16 & 0xFF) > 0x10) ? "true" : "false"); // fast press = on, slow press = off HttpPut((wchar_t*)L"censored.localhost", (wchar_t*)L"/api/censored/groups/3/action", (LPSTR)buffer); } /* Bathroom Light Switch */ } else if (!(dwParam1 >> 8 & 0xFF ^ 0x34)) { if ((dwParam1 >> 16 & 0xFF) != 0x00) { // ignore key off msg snprintf(buffer, 50, "{\"on\": %s}", ((dwParam1 >> 16 & 0xFF) > 0x10) ? "true" : "false"); // fast press = on, slow press = off HttpPut((wchar_t*)L"censored.localhost", (wchar_t*)L"/api/censored/groups/10/action", (LPSTR)buffer); } /* August Lock */ } else if (!(dwParam1 >> 8 & 0xFF ^ 0x35)) { if ((dwParam1 >> 16 & 0xFF) != 0x00) { // ignore key off msg if ((dwParam1 >> 16 & 0xFF) > 0x10) AugustLock(0); else AugustLock(1); // fast press = unlock, slow press = lock } /* Toggle Window */ } else if (!(dwParam1 >> 8 & 0xFF ^ 0x24)) { if ((dwParam1 >> 16 & 0xFF) != 0x00) { // ignore key off msg windowVisibility = !windowVisibility; ShowWindow(hWnd, windowVisibility); } } } break; default: break; } } void ChangeVolume(double volume) { IMMDeviceEnumerator* deviceEnumerator = NULL; IMMDevice* defaultDevice = NULL; IAudioEndpointVolume* endpointVolume = NULL; CoInitialize(NULL); CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID*)&deviceEnumerator); deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &defaultDevice); deviceEnumerator->Release(); deviceEnumerator = NULL; defaultDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (LPVOID*)&endpointVolume); defaultDevice->Release(); defaultDevice = NULL; endpointVolume->SetMasterVolumeLevelScalar((float)volume, NULL); endpointVolume->Release(); CoUninitialize(); } void HttpPut(wchar_t* host, wchar_t* path, LPSTR body) { DWORD dwSize = 0; DWORD dwDownloaded = 0; LPSTR pszOutBuffer; BOOL bResults = FALSE; HINTERNET hSession = NULL, hConnect = NULL, hRequest = NULL; hSession = WinHttpOpen(L"WinHTTP Example/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); if (hSession) hConnect = WinHttpConnect(hSession, host, INTERNET_DEFAULT_HTTP_PORT, 0); if (hConnect) hRequest = WinHttpOpenRequest(hConnect, L"PUT", path, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, NULL); if (hRequest) bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, body, strlen(body), strlen(body), 0); if (bResults) bResults = WinHttpReceiveResponse(hRequest, NULL); if (bResults) { do { // Check for available data. dwSize = 0; if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) printf("Error %u in WinHttpQueryDataAvailable.\n", GetLastError()); // Allocate space for the buffer. pszOutBuffer = new char[dwSize + 1]; if (!pszOutBuffer){ printf("Out of memory\n"); dwSize = 0; } else { // Read the data. ZeroMemory(pszOutBuffer, dwSize + 1); if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded)) printf("Error %u in WinHttpReadData.\n", GetLastError()); else // printf("%s", pszOutBuffer); // Free the memory allocated to the buffer. delete[] pszOutBuffer; } }while (dwSize > 0); } // Report any errors. if (!bResults) printf("Error %d has occurred.\n", GetLastError()); // Close any open handles. if (hRequest) WinHttpCloseHandle(hRequest); if (hConnect) WinHttpCloseHandle(hConnect); if (hSession) WinHttpCloseHandle(hSession); } void AugustLock(int lock) { DWORD dwSize = 0; DWORD dwDownloaded = 0; LPSTR pszOutBuffer; BOOL bResults = FALSE; HINTERNET hSession = NULL, hConnect = NULL, hRequest = NULL; hSession = WinHttpOpen(L"WinHTTP Example/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); if (hSession) hConnect = WinHttpConnect(hSession, L"api-production.august.com", INTERNET_DEFAULT_HTTPS_PORT, 0); if (hConnect) hRequest = WinHttpOpenRequest(hConnect, L"PUT", (lock) ? L"/remoteoperate/censored/lock" : L"/remoteoperate/censored/unlock", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE); if (hRequest) bResults = WinHttpAddRequestHeaders(hRequest, L"x-august-api-key:79fd0eb6-381d-4adf-95a0-47721289d1d9", (ULONG)-1L, WINHTTP_ADDREQ_FLAG_ADD); if (hRequest) bResults = WinHttpAddRequestHeaders(hRequest, L"Content-Type:application/json", (ULONG)-1L, WINHTTP_ADDREQ_FLAG_ADD); if (hRequest) bResults = WinHttpAddRequestHeaders(hRequest, L"x-august-access-token:censored", (ULONG)-1L, WINHTTP_ADDREQ_FLAG_ADD); if (hRequest) bResults = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0); if (bResults) bResults = WinHttpReceiveResponse(hRequest, NULL); if (bResults) { do { // Check for available data. dwSize = 0; if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) printf("Error %u in WinHttpQueryDataAvailable.\n", GetLastError()); // Allocate space for the buffer. pszOutBuffer = new char[dwSize + 1]; if (!pszOutBuffer) { printf("Out of memory\n"); dwSize = 0; } else { // Read the data. ZeroMemory(pszOutBuffer, dwSize + 1); if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded)) printf("Error %u in WinHttpReadData.\n", GetLastError()); else // printf("%s", pszOutBuffer); // Free the memory allocated to the buffer. delete[] pszOutBuffer; } } while (dwSize > 0); } // Report any errors. if (!bResults) printf("Error %d has occurred.\n", GetLastError()); // Close any open handles. if (hRequest) WinHttpCloseHandle(hRequest); if (hConnect) WinHttpCloseHandle(hConnect); if (hSession) WinHttpCloseHandle(hSession); } void KeyboardPress(int key) { INPUT ip; ip.type = INPUT_KEYBOARD; ip.ki.wScan = 0; ip.ki.time = 0; ip.ki.dwExtraInfo = 0; ip.ki.wVk = key; // Key ip.ki.dwFlags = 0; SendInput(1, &ip, sizeof(INPUT)); ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release SendInput(1, &ip, sizeof(INPUT)); }