123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519 |
- //#define PLUGIN_NAME //"Nullsoft Global Hotkeys"
- #define PLUGIN_VERSION L"1.97"
- // do this so we can get WM_APPCOMMAND support (needed in 1.6+)
- // (have to targetting xp sp1+ so we get the specific play & pause messages
- // though it'll work fine with win2k+ as those messages will never appear)
- //////#define _WIN32_WINNT 0x0501
- #include "gen_hotkeys.h"
- #include "ConfigDlg.h"
- #include "HotKey.h"
- #include "WACommands.h"
- #include <api/service/waServiceFactory.h>
- ///////////////////////////////////////////////////////////
- // Globals
- ///////////////////////////////////////////////////////////
- // The global plugin instance
- winampGeneralPurposePlugin psPlugin =
- {
- GPPHDR_VER_U,
- "nullsoft(gen_hotkeys.dll)",
- pluginInit,
- pluginConfig,
- hotkeysClear
- };
- // Winamp's window procdure
- WNDPROC lpWndProcOld = NULL;
- static int winampIsUnicode=false;
- static int appcommand=false;
- // hotkeys
- HOTKEY *g_hotkeys = NULL;
- DWORD g_dwHotkeys = 0;
- // mutex to prevent two gen_hotkeys
- HANDLE g_hMutex = NULL;
- LPARAM uShellHook = NULL;
- // wasabi based services for localisation support
- api_service *WASABI_API_SVC = 0;
- api_application *WASABI_API_APP = NULL;
- api_language *WASABI_API_LNG = 0;
- HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
- static prefsDlgRecW g_prefsItem = {0};
- static wchar_t g_titlestr[128];
- wchar_t *g_iniFile = 0;
- // don't forget to set DEFHKDS_NUM if you change this
- HOTKEY_DATA g_defhkds[] = {
- {MAKEWORD(VK_INSERT, HOTKEYF_ALT | HOTKEYF_CONTROL | HOTKEYF_EXT), -1, L"ghkdc play"},
- {MAKEWORD(VK_HOME, HOTKEYF_ALT | HOTKEYF_CONTROL | HOTKEYF_EXT), -1, L"ghkdc pause"},
- {MAKEWORD(VK_END, HOTKEYF_ALT | HOTKEYF_CONTROL | HOTKEYF_EXT), -1, L"ghkdc stop"},
- {MAKEWORD(VK_PRIOR, HOTKEYF_ALT | HOTKEYF_CONTROL | HOTKEYF_EXT), -1, L"ghkdc prev"},
- {MAKEWORD(VK_NEXT, HOTKEYF_ALT | HOTKEYF_CONTROL | HOTKEYF_EXT), -1, L"ghkdc next"},
- {MAKEWORD(VK_UP, HOTKEYF_ALT | HOTKEYF_CONTROL | HOTKEYF_EXT), -1, L"ghkdc vup"},
- {MAKEWORD(VK_DOWN, HOTKEYF_ALT | HOTKEYF_CONTROL | HOTKEYF_EXT), -1, L"ghkdc vdown"},
- {MAKEWORD(VK_RIGHT, HOTKEYF_ALT | HOTKEYF_CONTROL | HOTKEYF_EXT), -1, L"ghkdc forward"},
- {MAKEWORD(VK_LEFT, HOTKEYF_ALT | HOTKEYF_CONTROL | HOTKEYF_EXT), -1, L"ghkdc rewind"},
- {MAKEWORD('J', HOTKEYF_ALT | HOTKEYF_CONTROL | HOTKEYF_EXT), -1, L"ghkdc jump"},
- {MAKEWORD('L', HOTKEYF_ALT | HOTKEYF_CONTROL | HOTKEYF_EXT), -1, L"ghkdc file"},
- //multimedia keyboard stuff
- {2226, -1, L"ghkdc stop"},
- {2227, -1, L"ghkdc play/pause"},
- {2225, -1, L"ghkdc prev"},
- {2224, -1, L"ghkdc next"},
- };
- #define TIMER_ID 0x8855
- static int m_genhotkeys_add_ipc;
- ///////////////////////////////////////////////////////////
- // DLL entry function
- ///////////////////////////////////////////////////////////
- #ifndef _DEBUG
- BOOL WINAPI _DllMainCRTStartup(HINSTANCE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
- {
- DisableThreadLibraryCalls(hInst);
- return TRUE;
- }
- #endif
- ///////////////////////////////////////////////////////////
- // Plugin functions
- ///////////////////////////////////////////////////////////
- int pluginInit()
- {
- RegisterShellHookWindow(psPlugin.hwndParent);
- uShellHook = RegisterWindowMessage(TEXT("SHELLHOOK"));
- g_iniFile = (wchar_t*)SendMessage(psPlugin.hwndParent, WM_WA_IPC, 0, IPC_GETINIFILEW);
- // loader so that we can get the localisation service api for use
- WASABI_API_SVC = (api_service*)SendMessage(psPlugin.hwndParent, WM_WA_IPC, 0, IPC_GET_API_SERVICE);
- if (WASABI_API_SVC == (api_service*)1 ||
- NULL == WASABI_API_SVC)
- {
- return 1;
- }
- waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(applicationApiServiceGuid);
- if (sf) WASABI_API_APP = reinterpret_cast<api_application*>(sf->getInterface());
- sf = WASABI_API_SVC->service_getServiceByGuid(languageApiGUID);
- if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
- // need to have this initialised before we try to do anything with localisation features
- WASABI_API_START_LANG(psPlugin.hDllInstance,GenHotkeysLangGUID);
- m_genhotkeys_add_ipc = (int)SendMessage( psPlugin.hwndParent, WM_WA_IPC, (WPARAM) &"GenHotkeysAdd", IPC_REGISTER_WINAMP_IPCMESSAGE);
- static wchar_t szDescription[256];
- StringCchPrintfW(szDescription, ARRAYSIZE(szDescription),
- WASABI_API_LNGSTRINGW(IDS_NULLSOFT_GLOBAL_HOTKEYS), PLUGIN_VERSION);
- psPlugin.description = (char*)szDescription;
- appcommand = GetPrivateProfileIntW(L"gen_hotkeys", L"appcommand", 0, g_iniFile);
- // Save Winamp's window procedure
- winampIsUnicode = IsWindowUnicode(psPlugin.hwndParent);
- lpWndProcOld = (WNDPROC)(LONG_PTR)GetWindowLongPtr(psPlugin.hwndParent, GWLP_WNDPROC);
- if (winampIsUnicode)
- SetWindowLongPtrW(psPlugin.hwndParent, GWLP_WNDPROC, (LONGX86)(LONG_PTR)WndProc);
- else
- SetWindowLongPtrA(psPlugin.hwndParent, GWLP_WNDPROC, (LONGX86)(LONG_PTR)WndProc);
- InitCommands();
- SetTimer(psPlugin.hwndParent, TIMER_ID, 10, NULL); //call hotkeysInit() when all plugins are loaded
- //register prefs screen
- g_prefsItem.dlgID = IDD_CONFIG;
- g_prefsItem.name = WASABI_API_LNGSTRINGW_BUF(IDS_GHK_TITLE_STR,g_titlestr,128);
- g_prefsItem.proc = ConfigProc;
- g_prefsItem.hInst = WASABI_API_LNG_HINST;
- // delay the adding of this
- // for some reason when changing a lang pack it can cause the WM_DESTROY of ConfigProc
- // to be called which completely messes up the ghk list and so can wipe it :(
- SendMessage(psPlugin.hwndParent, WM_WA_IPC, (WPARAM) &g_prefsItem, IPC_ADD_PREFS_DLGW);
- return 0;
- }
- int hotkeysLoad(HOTKEY_DATA *hkds, DWORD num, int do_register, int verbose /*=1*/)
- {
- unsigned int uFailed = 0;
- delete [] g_hotkeys;
- g_hotkeys = NULL;
- if (num)
- {
- g_hotkeys = new HOTKEY[num];
- memset(g_hotkeys, 0, num * sizeof(HOTKEY));
- }
- if (!g_hotkeys)
- {
- g_dwHotkeys = 0;
- return 1;
- }
- g_dwHotkeys = num;
- wchar_t moreStr[64] = {0};
- WASABI_API_LNGSTRINGW_BUF(IDS_GHK_HOTKEY_REG_FAILED_MORE,moreStr,64);
- size_t bufLen = 256 + wcslen(moreStr) + 1;
- wchar_t* szFailed = (wchar_t*)malloc(bufLen*sizeof(wchar_t));
- WASABI_API_LNGSTRINGW_BUF(IDS_GHK_HOTKEY_REG_FAILED,szFailed,bufLen);
- DWORD dwLeft = 256 - lstrlenW(szFailed);
- DWORD dwFailedWithNoMsg = 0;
- for (DWORD i = 0; i < num; i++)
- {
- g_hotkeys[i].hkd = hkds[i];
- if (g_hotkeys[i].hkd.iCommand < 0)
- // action not loaded yet for this hotkey
- continue;
- if (do_register && RegisterHotkey(g_hotkeys + i))
- {
- if (verbose && dwLeft)
- {
- wchar_t szTemp[1024] = {0};
- bool unicode = 0;
- char* name = GetCommandName(g_hotkeys[i].hkd.iCommand, &unicode);
- StringCchPrintfW(szTemp, 1024, (unicode?L"\n\t%s":L"\n\t%S"), name);
- DWORD dwLen = lstrlenW(szTemp);
- if (dwLen < dwLeft)
- {
- StringCchCatW(szFailed, bufLen, szTemp);
- dwLeft -= dwLen;
- }
- else
- dwFailedWithNoMsg++;
- }
- g_hotkeys[i].failed = TRUE;
- uFailed++;
- }
- }
- if (verbose && uFailed)
- {
- if (dwFailedWithNoMsg)
- StringCchCatW(szFailed, bufLen, moreStr);
- HWND parent = (HWND)SendMessage(psPlugin.hwndParent, WM_WA_IPC, 0, IPC_GETDIALOGBOXPARENT);
- if (parent == 0 || parent == (HWND)1)
- parent=psPlugin.hwndParent;
- MessageBoxW(parent, szFailed, g_titlestr, MB_OK | MB_ICONSTOP | MB_TOPMOST);
- }
- free(szFailed);
- return uFailed;
- }
- static volatile LONG initted=0;
- void hotkeysInit()
- {
- if (initted)
- return;
- initted=1;
- int enabled = GetPrivateProfileIntW(L"gen_hotkeys", L"enabled", 0, g_iniFile);
- // base the mutex on the current winamp install
- // (makes it work better with mutliple winamp installs otherwise the older
- // "Winamp - gen_hotkeys.dll ^&*#@" mutex prevents different hotkeys from
- // being initialised between the different installs without going to prefs)
- char mutexStr[MAX_PATH] = {0}, ghkFilename[MAX_PATH] = {0};
- GetModuleFileName(psPlugin.hDllInstance, ghkFilename, MAX_PATH);
- StringCchPrintf(mutexStr, MAX_PATH, "Winamp - %s ^&*#@", ghkFilename);
- g_hMutex = CreateMutex(0, TRUE, mutexStr);
- if (GetLastError() == ERROR_ALREADY_EXISTS)
- enabled = 0;
- int i;
- for (i = 0; i < DEFHKDS_NUM; i++)
- {
- g_defhkds[i].iCommand = GetCommandIdx(g_defhkds[i].szCommand);
- g_defhkds[i].szCommand = 0;
- }
- int l = GetPrivateProfileIntW(L"gen_hotkeys", L"nbkeys", -1, g_iniFile);
- int ver = GetPrivateProfileIntW(L"gen_hotkeys", L"version", 1, g_iniFile);
- if (l != -1)
- {
- if (ver == 2)
- {
- HOTKEY_DATA *hkds = new HOTKEY_DATA[l]; // TODO: could alloca this
- if (hkds)
- {
- for (i = 0; i < l; i++)
- {
- wchar_t tmp[1024] = {0}, action[1024] = {0};
- StringCchPrintfW(tmp, 1024, L"action%d", i);
- GetPrivateProfileStringW(L"gen_hotkeys", tmp, L"", action, 1024, g_iniFile);
- StringCchPrintfW(tmp, 1024, L"hotkey%d", i);
- int hotkey = GetPrivateProfileIntW(L"gen_hotkeys", tmp, 0, g_iniFile);
- hkds[i].dwHotKey = hotkey;
- hkds[i].iCommand = GetCommandIdx(action);
- if (hkds[i].iCommand >= 0)
- hkds[i].szCommand = NULL;
- else
- hkds[i].szCommand = _wcsdup(action);
- }
- hotkeysLoad(hkds, l, enabled, 0);
- delete [] hkds;
- }
- }
- // legacy support
- else if (ver == 1)
- {
- HOTKEY_DATA *hkds = new HOTKEY_DATA[l]; // TODO: could alloca this
- if (hkds)
- {
- int nb = 0;
- for (i = 0;i < l;i++)
- {
- wchar_t tmp[512] = {0};
- StringCchPrintfW(tmp, 512, L"msg%d", i);
- unsigned int msg = GetPrivateProfileIntW(L"gen_hotkeys", tmp, 0, g_iniFile);
- if (msg)
- {
- StringCchPrintfW(tmp, 512, L"wparam%d", i);
- WPARAM wparam = GetPrivateProfileIntW(L"gen_hotkeys", tmp, 0, g_iniFile);
- StringCchPrintfW(tmp, 512, L"lparam%d", i);
- LPARAM lparam = GetPrivateProfileIntW(L"gen_hotkeys", tmp, 0, g_iniFile);
- for (int j = 0;WACommands[j].name;j++)
- {
- if (WACommands[j].uMsg == msg && WACommands[j].wParam == wparam && WACommands[j].lParam == lparam)
- {
- StringCchPrintfW(tmp, 512, L"hotkey%d", i);
- int hotkey = GetPrivateProfileIntW(L"gen_hotkeys", tmp, 0, g_iniFile);
- hkds[nb].dwHotKey = hotkey;
- hkds[nb].iCommand = j;
- hkds[nb].szCommand = NULL;
- nb++;
- break;
- }
- }
- }
- }
- hotkeysLoad(hkds, nb, enabled, 0);
- delete [] hkds;
- }
- }
- }
- else
- {
- // load defaults
- hotkeysLoad(g_defhkds, DEFHKDS_NUM, enabled, 0);
- }
- }
- void writePrivateProfileInt(wchar_t *section, int val)
- {
- wchar_t s[32] = {0};
- StringCchPrintfW(s, 32, L"%d", val);
- WritePrivateProfileStringW(L"gen_hotkeys", section, s, g_iniFile);
- }
- void hotkeysSave(HOTKEY_DATA *hkds, DWORD num)
- {
- int enabled = GetPrivateProfileIntW(L"gen_hotkeys", L"enabled", 0, g_iniFile);
- appcommand = GetPrivateProfileIntW(L"gen_hotkeys", L"appcommand", 0, g_iniFile);
- WritePrivateProfileStringW(L"gen_hotkeys", NULL, NULL, g_iniFile);
- writePrivateProfileInt(L"nbkeys", num);
- writePrivateProfileInt(L"version", 2);
- writePrivateProfileInt(L"enabled", enabled);
- writePrivateProfileInt(L"appcommand", appcommand);
- if (!hkds || !num)
- {
- return ;
- }
- for (size_t i = 0; i < num; i++)
- {
- wchar_t tmp[1024] = {0};
- StringCchPrintfW(tmp, 1024, L"action%d", i);
- if (hkds[i].iCommand >= 0)
- WritePrivateProfileStringW(L"gen_hotkeys", tmp, GetCommandId(hkds[i].iCommand), g_iniFile);
- else if (hkds[i].szCommand)
- WritePrivateProfileStringW(L"gen_hotkeys", tmp, hkds[i].szCommand, g_iniFile);
- StringCchPrintfW(tmp, 1024, L"hotkey%d", i);
- writePrivateProfileInt(tmp, hkds[i].dwHotKey);
- }
- }
- void pluginConfig()
- {
- SendMessage(psPlugin.hwndParent, WM_WA_IPC, (WPARAM) &g_prefsItem, IPC_OPENPREFSTOPAGE);
- }
- void hotkeysClear()
- {
- DeregisterShellHookWindow(psPlugin.hwndParent);
- if (!g_hotkeys)
- return;
- // Unregister all of the hot keys, and delete all of our unique hot key identifiers
- for (DWORD i = 0; i < g_dwHotkeys; i++)
- {
- UnregisterHotkey(g_hotkeys + i);
- }
- delete [] g_hotkeys;
- g_hotkeys = NULL;
- }
- ///////////////////////////////////////////////////////////
- // Plugin export function
- ///////////////////////////////////////////////////////////
- extern "C" __declspec(dllexport) winampGeneralPurposePlugin * winampGetGeneralPurposePlugin() { return &psPlugin; }
- ///////////////////////////////////////////////////////////
- // DLL Windows message handling procedure
- ///////////////////////////////////////////////////////////
- LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- if(message == uShellHook && appcommand && wParam == HSHELL_APPCOMMAND)
- {
- // WM_APPCOMMAND info:: http://msdn2.microsoft.com/en-us/library/ms646275.aspx
- int cmd = GET_APPCOMMAND_LPARAM(lParam);
- switch (cmd)
- {
- case APPCOMMAND_MEDIA_PLAY_PAUSE:
- {
- int playing = (int)SendMessage(psPlugin.hwndParent, WM_WA_IPC, 0, IPC_ISPLAYING);
- SendMessage(hwnd, WM_COMMAND, MAKEWPARAM((playing ? WINAMP_BUTTON3 : WINAMP_BUTTON2),0), 0);
- }
- break;
- case APPCOMMAND_MEDIA_NEXTTRACK:
- SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(WINAMP_BUTTON5,0), 0);
- return TRUE;
- case APPCOMMAND_MEDIA_PREVIOUSTRACK:
- SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(WINAMP_BUTTON1,0), 0);
- return TRUE;
- case APPCOMMAND_MEDIA_STOP:
- SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(WINAMP_BUTTON4,0), 0);
- return TRUE;
- case APPCOMMAND_VOLUME_DOWN:
- SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(WINAMP_VOLUMEDOWN,0), 0);
- return TRUE;
- case APPCOMMAND_VOLUME_UP:
- SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(WINAMP_VOLUMEUP,0), 0);
- return TRUE;
- /*case APPCOMMAND_VOLUME_MUTE:
- return TRUE;*/
- // info on play/pause (xp sp1+) commands:: http://msdn2.microsoft.com/en-us/library/bb417078.aspx
- case APPCOMMAND_MEDIA_PLAY:
- {
- int playing = (int)SendMessage(psPlugin.hwndParent, WM_WA_IPC, 0, IPC_ISPLAYING);
- // play if not currently playing/are stopped
- if(!playing) SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(WINAMP_BUTTON2,0), 0);
- // if paused then start playing again
- else if(playing == 3) SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(WINAMP_BUTTON3,0), 0);
- // otherwise do nothing if playing already (playing == 1)
- }
- return TRUE;
- case APPCOMMAND_MEDIA_PAUSE:
- {
- int playing = (int)SendMessage(psPlugin.hwndParent, WM_WA_IPC, 0, IPC_ISPLAYING);
- // if playing then we pause
- if(playing == 1) SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(WINAMP_BUTTON3,0), 0);
- // otherwise do nothing if already stopped or paused (playing == 0 || playing == 3)
- }
- return TRUE;
- case APPCOMMAND_MEDIA_FAST_FORWARD:
- SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(WINAMP_FFWD5S,0), 0);
- return TRUE;
- case APPCOMMAND_MEDIA_REWIND:
- SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(WINAMP_REW5S,0), 0);
- return TRUE;
- }
- }
- switch (message)
- {
- case WM_TIMER:
- if (wParam == TIMER_ID)
- {
- KillTimer(hwnd, TIMER_ID);
- hotkeysInit();
- return 0;
- }
- break;
- case WM_HOTKEY:
- if (g_hotkeys)
- {
- for (unsigned int i = 0; i < g_dwHotkeys; i++)
- {
- if (g_hotkeys[i].atom == wParam)
- {
- DoCommand(g_hotkeys[i].hkd.iCommand);
- return 0;
- }
- }
- }
- break;
- case WM_WA_IPC:
- if (lParam == m_genhotkeys_add_ipc && m_genhotkeys_add_ipc > 65536)
- {
- int cmd = AddCommand((genHotkeysAddStruct *) wParam);
- if (cmd > 0)
- {
- for (unsigned int i = 0; i < g_dwHotkeys; i++)
- {
- if (g_hotkeys[i].hkd.iCommand < 0
- && g_hotkeys[i].hkd.szCommand
- && !lstrcmpiW(g_hotkeys[i].hkd.szCommand, GetCommandId(cmd)))
- {
- g_hotkeys[i].hkd.iCommand = cmd;
- free(g_hotkeys[i].hkd.szCommand);
- g_hotkeys[i].hkd.szCommand = NULL;
- int enabled = GetPrivateProfileIntW(L"gen_hotkeys", L"enabled", 0, g_iniFile);
- if (enabled) RegisterHotkey(&g_hotkeys[i]);
- }
- }
- }
- return cmd;
- }
- // handles the weird inc/dec current rating (since it's locked to 0-5
- // we can just wrap around and correct the real value passed on to the api)
- else if(lParam == IPC_SETRATING && (wParam == -1 || wParam == 6))
- {
- LRESULT curRating = SendMessage(hwnd, WM_WA_IPC,
- SendMessage(hwnd, WM_WA_IPC, 0, IPC_GETLISTPOS),
- IPC_GETRATING);
- if(wParam == 6) // increment
- {
- wParam = curRating+1;
- }
- else // decrement
- {
- wParam = curRating-1;
- }
- }
- break;
- }
- // If we don't know how to handle this message, let WinAMP do it for us
- if (winampIsUnicode)
- return CallWindowProcW(lpWndProcOld, hwnd, message, wParam, lParam);
- else
- return CallWindowProcA(lpWndProcOld, hwnd, message, wParam, lParam);
- }
|