diff --git a/App.xaml.cs b/App.xaml.cs index c70f6fb..ebe3bff 100644 --- a/App.xaml.cs +++ b/App.xaml.cs @@ -37,7 +37,7 @@ namespace unison { _systray.Dispose(); _snapcast.LaunchOrExit(true); - _hotkeys.RemoveHotKeys(); + _hotkeys.RemoveHotkeys(); base.OnExit(e); } } diff --git a/Handlers/HotkeyHandler.cs b/Handlers/HotkeyHandler.cs index c0680a2..3d57eb2 100644 --- a/Handlers/HotkeyHandler.cs +++ b/Handlers/HotkeyHandler.cs @@ -15,21 +15,168 @@ namespace unison private const int HOTKEY_ID = 9000; - // modifiers - private const uint MOD_NONE = 0x0000; - private const uint MOD_ALT = 0x0001; - private const uint MOD_CONTROL = 0x0002; - private const uint MOD_SHIFT = 0x0004; - private const uint MOD_WIN = 0x0008; + public enum MOD : int + { + None = 0x0000, + Alt = 0x0001, + Control = 0x0002, + Shift = 0x0004, + //Win = 0x0008 + }; // reference => https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes - private const uint VK_MEDIA_PREV_TRACK = 0xB1; - private const uint VK_MEDIA_NEXT_TRACK = 0xB0; - private const uint VK_MEDIA_PLAY_PAUSE = 0xB3; - private const uint VK_VOLUME_UP = 0xAF; - private const uint VK_VOLUME_DOWN = 0xAE; - private const uint VK_VOLUME_MUTE = 0xAD; - private const uint VK_ENTER = 0x0D; + public enum VK : int + { + None = 0x00, + Back = 0x08, + Tab = 0x09, + Clear = 0x0c, + Return = 0x0d, + Menu = 0x12, + Pause = 0x13, + Capital = 0x14, + Kana = 0x15, + Hangul = 0x15, + Junja = 0x17, + Final = 0x18, + Hanja = 0x19, + Kanji = 0x19, + Escape = 0x1b, + Convert = 0x1c, + NonConvert = 0x1d, + Accept = 0x1e, + ModeChange = 0x1f, + Space = 0x20, + Prior = 0x21, + Next = 0x22, + End = 0x23, + Home = 0x24, + Left = 0x25, + Up = 0x26, + Right = 0x27, + Down = 0x28, + Select = 0x29, + Print = 0x2a, + Execute = 0x2b, + Snapshot = 0x2c, + Insert = 0x2d, + Delete = 0x2e, + Help = 0x2f, + NumRow0 = 0x30, + NumRow1 = 0x31, + NumRow2 = 0x32, + NumRow3 = 0x33, + NumRow4 = 0x34, + NumRow5 = 0x35, + NumRow6 = 0x36, + NumRow7 = 0x37, + NumRow8 = 0x38, + NumRow9 = 0x39, + A = 0x41, + B = 0x42, + C = 0x43, + D = 0x44, + E = 0x45, + F = 0x46, + G = 0x47, + H = 0x48, + I = 0x49, + J = 0x4a, + K = 0x4b, + L = 0x4c, + M = 0x4d, + N = 0x4e, + O = 0x4f, + P = 0x50, + Q = 0x51, + R = 0x52, + S = 0x53, + T = 0x54, + U = 0x55, + V = 0x56, + W = 0x57, + X = 0x58, + Y = 0x59, + Z = 0x5a, + Apps = 0x5d, + Sleep = 0x5f, + NumPad0 = 0x60, + NumPad1 = 0x61, + NumPad2 = 0x62, + NumPad3 = 0x63, + NumPad4 = 0x64, + NumPad5 = 0x65, + NumPad6 = 0x66, + NumPad7 = 0x67, + NumPad8 = 0x68, + NumPad9 = 0x69, + Multiply = 0x6a, + Add = 0x6b, + Separator = 0x6c, + Subtract = 0x6d, + Decimal = 0x6e, + Divide = 0x6f, + F1 = 0x70, + F2 = 0x71, + F3 = 0x72, + F4 = 0x73, + F5 = 0x74, + F6 = 0x75, + F7 = 0x76, + F8 = 0x77, + F9 = 0x78, + F10 = 0x79, + F11 = 0x7a, + F12 = 0x7b, + F13 = 0x7c, + F14 = 0x7d, + F15 = 0x7e, + F16 = 0x7f, + F17 = 0x80, + F18 = 0x81, + F19 = 0x82, + F20 = 0x83, + F21 = 0x84, + F22 = 0x85, + F23 = 0x86, + F24 = 0x87, + NumLock = 0x90, + Scroll = 0x91, + LMenu = 0xa4, + RMenu = 0xa5, + BrowserBack = 0xa6, + BrowserForward = 0xa7, + BrowserRefresh = 0xa8, + BrowserStop = 0xa9, + BrowserSearch = 0xaa, + BrowserFavorites = 0xab, + BrowserHome = 0xac, + VolumeMute = 0xad, + VolumeDown = 0xae, + VolumeUp = 0xaf, + MediaNextTrack = 0xb0, + MediaPreviousTrack = 0xb1, + MediaStop = 0xb2, + MediaPlayPause = 0xb3, + LaunchMail = 0xb4, + LaunchMediaSelect = 0xb5, + LaunchApp1 = 0xb6, + LaunchApp2 = 0xb7, + }; + + public struct HotkeyPair + { + public MOD mod; + public VK vk; + + public HotkeyPair(MOD _mod, VK _vk) { mod = _mod; vk = _vk; } + + public uint GetMOD() { return (uint)mod; } + public uint GetVK() { return (uint)vk; } + + public void SetMOD(MOD modmod) { mod = modmod; } + public void SetVK(VK vkvk) { vk = vkvk; } + } private MainWindow _appWindow; private readonly MPDHandler _mpd; @@ -37,9 +184,26 @@ namespace unison private IntPtr _windowHandle; private HwndSource _source; + public HotkeyPair _NextTrack; + public HotkeyPair _PreviousTrack; + public HotkeyPair _PlayPause; + public HotkeyPair _VolumeUp; + public HotkeyPair _VolumeDown; + public HotkeyPair _VolumeMute; + public HotkeyPair _ShowWindow; + public HotkeyHandler() { _mpd = (MPDHandler)Application.Current.Properties["mpd"]; + + // get shortcuts from settings + _NextTrack = new HotkeyPair((MOD)Properties.Settings.Default.nextTrack_mod, (VK)Properties.Settings.Default.nextTrack_vk); + _PreviousTrack = new HotkeyPair((MOD)Properties.Settings.Default.previousTrack_mod, (VK)Properties.Settings.Default.previousTrack_vk); + _PlayPause = new HotkeyPair((MOD)Properties.Settings.Default.playPause_mod, (VK)Properties.Settings.Default.playPause_vk); + _VolumeUp = new HotkeyPair((MOD)Properties.Settings.Default.volumeUp_mod, (VK)Properties.Settings.Default.volumeUp_vk); + _VolumeDown = new HotkeyPair((MOD)Properties.Settings.Default.volumeDown_mod, (VK)Properties.Settings.Default.volumeDown_vk); + _VolumeMute = new HotkeyPair((MOD)Properties.Settings.Default.volumeMute_mod, (VK)Properties.Settings.Default.volumeMute_vk); + _ShowWindow = new HotkeyPair((MOD)Properties.Settings.Default.showWindow_mod, (VK)Properties.Settings.Default.showWindow_vk); } public void Activate(Window win) @@ -48,18 +212,28 @@ namespace unison { _windowHandle = new WindowInteropHelper(win).Handle; _source = HwndSource.FromHwnd(_windowHandle); - _source.AddHook(HwndHook); - - RegisterHotKey(_windowHandle, HOTKEY_ID, MOD_CONTROL, VK_MEDIA_PREV_TRACK); - RegisterHotKey(_windowHandle, HOTKEY_ID, MOD_CONTROL, VK_MEDIA_NEXT_TRACK); - RegisterHotKey(_windowHandle, HOTKEY_ID, MOD_CONTROL, VK_MEDIA_PLAY_PAUSE); - RegisterHotKey(_windowHandle, HOTKEY_ID, MOD_CONTROL, VK_VOLUME_UP); - RegisterHotKey(_windowHandle, HOTKEY_ID, MOD_CONTROL, VK_VOLUME_DOWN); - RegisterHotKey(_windowHandle, HOTKEY_ID, MOD_CONTROL, VK_VOLUME_MUTE); - RegisterHotKey(_windowHandle, HOTKEY_ID, MOD_CONTROL | MOD_ALT, VK_ENTER); + AddHotkeys(); } } + public void AddHotkeys() + { + _source.AddHook(HwndHook); + RegisterHotKey(_windowHandle, HOTKEY_ID, _NextTrack.GetMOD(), _NextTrack.GetVK()); + RegisterHotKey(_windowHandle, HOTKEY_ID, _PreviousTrack.GetMOD(), _PreviousTrack.GetVK()); + RegisterHotKey(_windowHandle, HOTKEY_ID, _PlayPause.GetMOD(), _PlayPause.GetVK()); + RegisterHotKey(_windowHandle, HOTKEY_ID, _VolumeUp.GetMOD(), _VolumeUp.GetVK()); + RegisterHotKey(_windowHandle, HOTKEY_ID, _VolumeDown.GetMOD(), _VolumeDown.GetVK()); + RegisterHotKey(_windowHandle, HOTKEY_ID, _VolumeMute.GetMOD(), _VolumeMute.GetVK()); + RegisterHotKey(_windowHandle, HOTKEY_ID, _ShowWindow.GetMOD(), _ShowWindow.GetVK()); + } + + public void RemoveHotkeys() + { + _source.RemoveHook(HwndHook); + UnregisterHotKey(_windowHandle, HOTKEY_ID); + } + private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { const int WM_HOTKEY = 0x0312; @@ -67,61 +241,48 @@ namespace unison if (msg == WM_HOTKEY && wParam.ToInt32() == HOTKEY_ID) { uint vkey = ((uint)lParam >> 16) & 0xFFFF; - switch (vkey) - { - case VK_MEDIA_NEXT_TRACK: - _mpd.Next(); - break; - case VK_MEDIA_PREV_TRACK: - _mpd.Prev(); - break; - case VK_VOLUME_DOWN: - _mpd.VolumeDown(); - break; - case VK_VOLUME_UP: - _mpd.VolumeUp(); - break; - case VK_VOLUME_MUTE: - _mpd.VolumeMute(); - break; - case VK_MEDIA_PLAY_PAUSE: - _mpd.PlayPause(); - break; - case VK_ENTER: - if (_appWindow == null) - _appWindow = (MainWindow)Application.Current.MainWindow; - if (_appWindow.WindowState == WindowState.Minimized) + if (vkey == _NextTrack.GetVK()) + _mpd.Next(); + else if (vkey == _PreviousTrack.GetVK()) + _mpd.Prev(); + else if (vkey == _PlayPause.GetVK()) + _mpd.PlayPause(); + else if (vkey == _VolumeUp.GetVK()) + _mpd.VolumeUp(); + else if (vkey == _VolumeDown.GetVK()) + _mpd.VolumeDown(); + else if (vkey == _VolumeMute.GetVK()) + _mpd.VolumeMute(); + else if (vkey == _ShowWindow.GetVK()) + { + if (_appWindow == null) + _appWindow = (MainWindow)Application.Current.MainWindow; + + if (_appWindow.WindowState == WindowState.Minimized) + { + _appWindow.Show(); + _appWindow.Activate(); + _appWindow.WindowState = WindowState.Normal; + } + else + { + if (_appWindow.IsActive) + { + _appWindow.Hide(); + _appWindow.WindowState = WindowState.Minimized; + } + else // not minimized but not in front { _appWindow.Show(); _appWindow.Activate(); _appWindow.WindowState = WindowState.Normal; } - else - { - if (_appWindow.IsActive) - { - _appWindow.Hide(); - _appWindow.WindowState = WindowState.Minimized; - } - else // not minimized but not in front - { - _appWindow.Show(); - _appWindow.Activate(); - _appWindow.WindowState = WindowState.Normal; - } - } - break; + } } handled = true; } return IntPtr.Zero; } - - public void RemoveHotKeys() - { - _source.RemoveHook(HwndHook); - UnregisterHotKey(_windowHandle, HOTKEY_ID); - } } } \ No newline at end of file diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs index 35adc82..03b9275 100644 --- a/Properties/Settings.Designer.cs +++ b/Properties/Settings.Designer.cs @@ -118,5 +118,173 @@ namespace unison.Properties { this["volume_offset"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("2")] + public uint nextTrack_mod { + get { + return ((uint)(this["nextTrack_mod"])); + } + set { + this["nextTrack_mod"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("176")] + public uint nextTrack_vk { + get { + return ((uint)(this["nextTrack_vk"])); + } + set { + this["nextTrack_vk"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("2")] + public uint previousTrack_mod { + get { + return ((uint)(this["previousTrack_mod"])); + } + set { + this["previousTrack_mod"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("177")] + public uint previousTrack_vk { + get { + return ((uint)(this["previousTrack_vk"])); + } + set { + this["previousTrack_vk"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("2")] + public uint playPause_mod { + get { + return ((uint)(this["playPause_mod"])); + } + set { + this["playPause_mod"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("179")] + public uint playPause_vk { + get { + return ((uint)(this["playPause_vk"])); + } + set { + this["playPause_vk"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("2")] + public uint volumeUp_mod { + get { + return ((uint)(this["volumeUp_mod"])); + } + set { + this["volumeUp_mod"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("175")] + public uint volumeUp_vk { + get { + return ((uint)(this["volumeUp_vk"])); + } + set { + this["volumeUp_vk"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("2")] + public uint volumeDown_mod { + get { + return ((uint)(this["volumeDown_mod"])); + } + set { + this["volumeDown_mod"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("174")] + public uint volumeDown_vk { + get { + return ((uint)(this["volumeDown_vk"])); + } + set { + this["volumeDown_vk"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("2")] + public uint volumeMute_mod { + get { + return ((uint)(this["volumeMute_mod"])); + } + set { + this["volumeMute_mod"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("173")] + public uint volumeMute_vk { + get { + return ((uint)(this["volumeMute_vk"])); + } + set { + this["volumeMute_vk"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("3")] + public uint showWindow_mod { + get { + return ((uint)(this["showWindow_mod"])); + } + set { + this["showWindow_mod"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("13")] + public uint showWindow_vk { + get { + return ((uint)(this["showWindow_vk"])); + } + set { + this["showWindow_vk"] = value; + } + } } } diff --git a/Properties/Settings.settings b/Properties/Settings.settings index 4a045b9..89920b8 100644 --- a/Properties/Settings.settings +++ b/Properties/Settings.settings @@ -26,5 +26,47 @@ 5 + + 2 + + + 176 + + + 2 + + + 177 + + + 2 + + + 179 + + + 2 + + + 175 + + + 2 + + + 174 + + + 2 + + + 173 + + + 3 + + + 13 + \ No newline at end of file diff --git a/README.md b/README.md index df02576..d217ea4 100644 --- a/README.md +++ b/README.md @@ -37,13 +37,12 @@ Through [Radio-Browser](https://www.radio-browser.info), a community database, y ### Missing features -* Custom shortcuts. * MPD passwords: I don't really see the point, but if asked, I will integrate them. -* Any sort of playlist and queue management. I use other software to do it, but I might implement them at some point. ### Wanted features * A complete shuffle system based on set criteria, aka a smart playlist. +* Any sort of playlist and queue management. I use other software to do it, but I will implement them at some point. ## Translations diff --git a/Views/Settings.xaml b/Views/Settings.xaml index f612775..61bf055 100644 --- a/Views/Settings.xaml +++ b/Views/Settings.xaml @@ -109,11 +109,12 @@ - + - + + @@ -126,23 +127,79 @@ + - - - - - - - + + + + + + + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +