From 166056799c20ec66cdf94124e8c8cb3ef8114c84 Mon Sep 17 00:00:00 2001 From: MichaÅ‚ CichoÅ„ Date: Fri, 3 May 2019 16:57:20 +0200 Subject: Add support for hotkeys. #20 Hotkeys can be assigned to action in configuration file ex: hk_ = g + shift + alt + ctrl --- src/hotkey.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/hotkey.h | 53 +++++++++++++++++++++++++ src/main.c | 52 ++++++++++++++++++++++++- src/settings.c | 15 ++++++++ src/ui_readline.c | 20 +++++----- src/ui_readline.h | 3 ++ 6 files changed, 245 insertions(+), 11 deletions(-) create mode 100644 src/hotkey.c create mode 100644 src/hotkey.h diff --git a/src/hotkey.c b/src/hotkey.c new file mode 100644 index 0000000..b630b88 --- /dev/null +++ b/src/hotkey.c @@ -0,0 +1,113 @@ +/* +Copyright (c) 2019 + Micha³ Cichoñ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "hotkey.h" +#include +#include +#include +#include +#include + +static BarHotKey_t* g_HotKeys = NULL; +static int g_HotKeyCapacity = 0; +static int g_HotKeyCount = 0; + +void BarHotKeyInit () +{ +} + +void BarHotKeyDestroy () +{ +} + +void BarHotKeyPool (BarHotKeyHandler handler, void * userData) +{ + MSG msg = {0}; + while (PeekMessage(&msg, NULL, WM_HOTKEY, WM_HOTKEY, PM_REMOVE) != 0) + { + int id = (int)msg.wParam; + if (id < 0) + continue; + + handler(id, userData); + } +} + +bool BarHotKeyRegister (BarHotKey_t hk) +{ + UINT modifiers = 0; + SHORT mappedVirtualKey = VkKeyScanA(tolower(hk.key)); + BYTE keyCode = LOBYTE(mappedVirtualKey); + if (keyCode == 0) + return false; + + if (hk.mods & BAR_HK_MOD_SHIFT) + modifiers |= MOD_SHIFT; + if (hk.mods & BAR_HK_MOD_ALT) + modifiers |= MOD_ALT; + if (hk.mods & BAR_HK_MOD_CTRL) + modifiers |= MOD_CONTROL; + if (hk.mods & BAR_HK_MOD_WIN) + modifiers |= MOD_WIN; + + modifiers |= /*MOD_NOREPEAT*/0x4000; + + return RegisterHotKey(NULL, hk.id, modifiers, keyCode); +} + +void BarHotKeyUnregister (int id) +{ + UnregisterHotKey(NULL, id); +} + +bool BarHotKeyParse (BarHotKey_t* result, const char *value) +{ + BarHotKey_t parsed = { 0 }; + const char* p = value; + size_t s = 0; + + while ((s = strcspn(p, " +")) > 0) + { + if ((s == 4 && strnicmp(p, "ctrl", 4) == 0) || (s == 7 && strnicmp(p, "control", 7) == 0)) + parsed.mods |= BAR_HK_MOD_CTRL; + else if ((s == 5 && strnicmp(p, "shift", 5) == 0)) + parsed.mods |= BAR_HK_MOD_SHIFT; + else if ((s == 3 && strnicmp(p, "alt", 3) == 0)) + parsed.mods |= BAR_HK_MOD_ALT; + else if (s == 1) + parsed.key = *p; + else + return false; + + p += s; + p += strspn(p, " +"); + } + + if (parsed.key == 0) + return false; + + result->key = parsed.key; + result->mods = parsed.mods; + + return true; +} \ No newline at end of file diff --git a/src/hotkey.h b/src/hotkey.h new file mode 100644 index 0000000..fb59bc0 --- /dev/null +++ b/src/hotkey.h @@ -0,0 +1,53 @@ +/* +Copyright (c) 2019 + Micha³ Cichoñ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +# pragma once + +#include "config.h" +#include +#include +#include + +typedef enum { + BAR_HK_MOD_NONE = 0, + BAR_HK_MOD_SHIFT = 1, + BAR_HK_MOD_ALT = 2, + BAR_HK_MOD_CTRL = 4, + BAR_HK_MOD_WIN = 8 +} BarHotKeyMods_t; + +typedef struct { + int id; + char key; + BarHotKeyMods_t mods; +} BarHotKey_t; + +typedef void (*BarHotKeyHandler)(int, void *); + +void BarHotKeyInit (); +void BarHotKeyDestroy (); +void BarHotKeyPool (BarHotKeyHandler, void *); +bool BarHotKeyRegister (BarHotKey_t); +void BarHotKeyUnregister (int); +bool BarHotKeyParse (BarHotKey_t* result, const char* value); + diff --git a/src/main.c b/src/main.c index a75388e..6dacba5 100644 --- a/src/main.c +++ b/src/main.c @@ -28,6 +28,7 @@ THE SOFTWARE. #include "main.h" #include "console.h" +#include "hotkey.h" #include "ui.h" #include "ui_dispatch.h" #include "ui_readline.h" @@ -179,17 +180,61 @@ static void BarMainGetInitialStation (BarApp_t *app) { } } +static int BarMainHandleVirtualKey(int virtualKey, void *userData) +{ + BarApp_t *app = (BarApp_t *)userData; + + switch (virtualKey) + { + case /*VK_VOLUME_MUTE*/ 0xAD: return 0; + case /*VK_VOLUME_DOWN*/ 0xAE: return 0;//app->settings.keys[BAR_KS_VOLDOWN]; + case /*VK_VOLUME_UP*/ 0xAF: return 0;//app->settings.keys[BAR_KS_VOLUP]; + case /*VK_MEDIA_NEXT_TRACK*/ 0xB0: return 0;//app->settings.keys[BAR_KS_SKIP]; + case /*VK_MEDIA_PREV_TRACK*/ 0xB1: return 0; + case /*VK_MEDIA_STOP*/ 0xB2: return 0; + case /*VK_MEDIA_PLAY_PAUSE*/ 0xB3: return 0;//app->settings.keys[BAR_KS_PLAYPAUSE]; + case /*VK_LAUNCH_MAIL*/ 0xB4: return 0; + case /*VK_LAUNCH_MEDIA_SELECT*/ 0xB5: return 0; + case /*VK_LAUNCH_APP1*/ 0xB6: return 0; + case /*VK_LAUNCH_APP2*/ 0xB7: return 0; + default: return 0; + } +} + +static void BarMainHotKeyHandler(int hotKeyId, void *userData) +{ + if (hotKeyId == 0) + return; + + BarApp_t *app = (BarApp_t *)userData; + + BarUiDispatch(app, app->settings.keys[hotKeyId], app->curStation, app->playlist, true, + BAR_DC_GLOBAL); +} + /* wait for user rl */ static void BarMainHandleUserInput(BarApp_t *app) { char buf[2]; - if (BarReadline(buf, sizeof(buf), NULL, app->rl, - BAR_RL_FULLRETURN | BAR_RL_NOECHO, 1) > 0) + size_t readSize = 0; + + BarReadlineSetVirtualKeyHandler(app->rl, BarMainHandleVirtualKey, app); + + readSize = BarReadline(buf, sizeof(buf), NULL, app->rl, + BAR_RL_FULLRETURN | BAR_RL_NOECHO, 1); + + BarReadlineSetVirtualKeyHandler(app->rl, NULL, NULL); + + if (readSize > 0) { BarUiDispatch(app, buf[0], app->curStation, app->playlist, true, BAR_DC_GLOBAL); } + else + { + BarHotKeyPool(BarMainHotKeyHandler, app); + } } /* fetch new playlist @@ -375,6 +420,8 @@ int main(int argc, char **argv) BarConsoleSetTitle(TITLE); + BarHotKeyInit(); + /* init some things */ BarSettingsInit(&app.settings); BarSettingsRead(&app.settings); @@ -432,6 +479,7 @@ int main(int argc, char **argv) HttpDestroy(app.http2); BarPlayer2Destroy(app.player); BarSettingsDestroy(&app.settings); + BarHotKeyDestroy(); BarConsoleDestroy(); return 0; diff --git a/src/settings.c b/src/settings.c index affb7f2..a2ce3fb 100644 --- a/src/settings.c +++ b/src/settings.c @@ -29,6 +29,7 @@ THE SOFTWARE. #include "config.h" #include "ui.h" #include "ui_dispatch.h" +#include "hotkey.h" #include #include #include @@ -340,6 +341,20 @@ void BarSettingsRead (BarSettings_t *settings) { break; } } + } else if (memcmp ("hk_act_", key, 7) == 0) { + size_t i; + char* actionKey = key + 3; + /* keyboard shortcuts */ + for (i = 0; i < BAR_KS_COUNT; i++) { + if (streq (dispatchActions[i].configKey, actionKey)) { + BarHotKey_t hk = { 0 }; + if (BarHotKeyParse(&hk, val)) { + hk.id = i; + BarHotKeyRegister(hk); + } + break; + } + } } else if (streq ("audio_quality", key)) { if (streq (val, "low")) { settings->audioQuality = PIANO_AQ_LOW; diff --git a/src/ui_readline.c b/src/ui_readline.c index 5d6b7a7..687258a 100644 --- a/src/ui_readline.c +++ b/src/ui_readline.c @@ -75,6 +75,8 @@ static inline int BarReadlineEncodeUtf8 (int codePoint, char* utf8) { struct _BarReadline_t { DWORD DefaultAttr; + BarVirtualKeyHandler VirtualKeyHandler; + void *VirtualKeyHandlerUserData; }; void BarReadlineInit(BarReadline_t* rl) { @@ -85,6 +87,11 @@ void BarReadlineInit(BarReadline_t* rl) { void BarReadlineDestroy(BarReadline_t rl) { } +void BarReadlineSetVirtualKeyHandler(BarReadline_t rl, BarVirtualKeyHandler handler, void *ud) { + rl->VirtualKeyHandler = handler; + rl->VirtualKeyHandlerUserData = ud; +} + /* return size of previous UTF-8 character */ static size_t BarReadlinePrevUtf8 (char *ptr) { @@ -248,16 +255,11 @@ size_t BarReadline (char *buf, const size_t bufSize, const char *mask, char encodedCodePoint[5]; int encodedCodePointLength; - /* - if (keyCode == VK_MEDIA_PLAY_PAUSE) { - codePoint = 'p'; - PlaySoundA("SystemNotification", NULL, SND_ASYNC); - } - else if (keyCode == VK_MEDIA_NEXT_TRACK) { - codePoint = 'n'; - PlaySoundA("SystemNotification", NULL, SND_ASYNC); + if (input->VirtualKeyHandler != NULL) { + int newCodePoint = input->VirtualKeyHandler(keyCode, input->VirtualKeyHandlerUserData); + if (newCodePoint != 0) + codePoint = newCodePoint; } - */ if (codePoint <= 0x1F) break; diff --git a/src/ui_readline.h b/src/ui_readline.h index 83214b9..bb2772a 100644 --- a/src/ui_readline.h +++ b/src/ui_readline.h @@ -36,8 +36,11 @@ typedef enum { typedef struct _BarReadline_t *BarReadline_t; +typedef int (*BarVirtualKeyHandler)(int, void*); + void BarReadlineInit(BarReadline_t*); void BarReadlineDestroy(BarReadline_t); +void BarReadlineSetVirtualKeyHandler(BarReadline_t, BarVirtualKeyHandler, void *); size_t BarReadline (char *, const size_t, const char *, BarReadline_t, const BarReadlineFlags_t, int); size_t BarReadlineStr (char *, const size_t, -- cgit v1.2.3