1 /* 2 KeePass Password Safe - The Open-Source Password Manager 3 Copyright (C) 2003-2021 Dominik Reichl <dominik.reichl@t-online.de> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 using System; 21 using System.Collections.Generic; 22 using System.Diagnostics; 23 using System.Runtime.InteropServices; 24 using System.Text; 25 using System.Windows.Forms; 26 27 using KeePass.App; 28 using KeePass.Forms; 29 using KeePass.Native; 30 using KeePass.Resources; 31 using KeePass.UI; 32 33 using KeePassLib; 34 using KeePassLib.Utility; 35 36 using NativeLib = KeePassLib.Native.NativeLib; 37 38 namespace KeePass.Util 39 { 40 public static class HotKeyManager 41 { 42 private static Form m_fRecvWnd = null; 43 private static Dictionary<int, Keys> m_vRegKeys = new Dictionary<int, Keys>(); 44 45 // private static NativeMethods.BindKeyHandler m_hOnHotKey = 46 // new NativeMethods.BindKeyHandler(HotKeyManager.OnHotKey); 47 48 // public static Form ReceiverWindow 49 // { 50 // get { return m_fRecvWnd; } 51 // set { m_fRecvWnd = value; } 52 // } 53 Initialize(Form fRecvWnd)54 public static bool Initialize(Form fRecvWnd) 55 { 56 m_fRecvWnd = fRecvWnd; 57 58 // if(NativeLib.IsUnix()) 59 // { 60 // try { NativeMethods.tomboy_keybinder_init(); } 61 // catch(Exception) { Debug.Assert(false); return false; } 62 // } 63 64 return true; 65 } 66 RegisterHotKey(int nId, Keys kKey)67 public static bool RegisterHotKey(int nId, Keys kKey) 68 { 69 UnregisterHotKey(nId); 70 71 uint uMod = 0; 72 if((kKey & Keys.Shift) != Keys.None) uMod |= NativeMethods.MOD_SHIFT; 73 if((kKey & Keys.Alt) != Keys.None) uMod |= NativeMethods.MOD_ALT; 74 if((kKey & Keys.Control) != Keys.None) uMod |= NativeMethods.MOD_CONTROL; 75 76 uint vkCode = (uint)(kKey & Keys.KeyCode); 77 if(vkCode == (uint)Keys.None) return false; // Don't register mod keys only 78 79 try 80 { 81 if(!NativeLib.IsUnix()) 82 { 83 if(NativeMethods.RegisterHotKey(m_fRecvWnd.Handle, nId, uMod, vkCode)) 84 { 85 m_vRegKeys[nId] = kKey; 86 return true; 87 } 88 } 89 else // Unix 90 { 91 // NativeMethods.tomboy_keybinder_bind(EggAccKeysToString(kKey), 92 // m_hOnHotKey); 93 // m_vRegKeys[nId] = kKey; 94 // return true; 95 } 96 } 97 catch(Exception) { Debug.Assert(false); } 98 99 return false; 100 } 101 UnregisterHotKey(int nId)102 public static bool UnregisterHotKey(int nId) 103 { 104 if(m_vRegKeys.ContainsKey(nId)) 105 { 106 // Keys k = m_vRegKeys[nId]; 107 m_vRegKeys.Remove(nId); 108 109 try 110 { 111 bool bResult; 112 if(!NativeLib.IsUnix()) 113 bResult = NativeMethods.UnregisterHotKey(m_fRecvWnd.Handle, nId); 114 else // Unix 115 { 116 // NativeMethods.tomboy_keybinder_unbind(EggAccKeysToString(k), 117 // m_hOnHotKey); 118 // bResult = true; 119 bResult = false; 120 } 121 122 // Debug.Assert(bResult); 123 return bResult; 124 } 125 catch(Exception) { Debug.Assert(false); } 126 } 127 128 return false; 129 } 130 UnregisterAll()131 public static void UnregisterAll() 132 { 133 List<int> vIDs = new List<int>(m_vRegKeys.Keys); 134 foreach(int nID in vIDs) UnregisterHotKey(nID); 135 136 Debug.Assert(m_vRegKeys.Count == 0); 137 } 138 IsHotKeyRegistered(Keys kKey, bool bGlobal)139 public static bool IsHotKeyRegistered(Keys kKey, bool bGlobal) 140 { 141 if(m_vRegKeys.ContainsValue(kKey)) return true; 142 if(!bGlobal) return false; 143 144 int nID = AppDefs.GlobalHotKeyId.TempRegTest; 145 if(!RegisterHotKey(nID, kKey)) return true; 146 147 UnregisterHotKey(nID); 148 return false; 149 } 150 151 /* private static void OnHotKey(string strKey, IntPtr lpUserData) 152 { 153 if(string.IsNullOrEmpty(strKey)) return; 154 if(strKey.IndexOf(@"<Release>", StrUtil.CaseIgnoreCmp) >= 0) return; 155 156 if(m_fRecvWnd != null) 157 { 158 MainForm mf = (m_fRecvWnd as MainForm); 159 if(mf == null) { Debug.Assert(false); return; } 160 161 Keys k = EggAccStringToKeys(strKey); 162 foreach(KeyValuePair<int, Keys> kvp in m_vRegKeys) 163 { 164 if(kvp.Value == k) mf.HandleHotKey(kvp.Key); 165 } 166 } 167 else { Debug.Assert(false); } 168 } 169 170 private static Keys EggAccStringToKeys(string strKey) 171 { 172 if(string.IsNullOrEmpty(strKey)) return Keys.None; 173 174 Keys k = Keys.None; 175 176 if(strKey.IndexOf(@"<Alt>", StrUtil.CaseIgnoreCmp) >= 0) 177 k |= Keys.Alt; 178 if((strKey.IndexOf(@"<Ctl>", StrUtil.CaseIgnoreCmp) >= 0) || 179 (strKey.IndexOf(@"<Ctrl>", StrUtil.CaseIgnoreCmp) >= 0) || 180 (strKey.IndexOf(@"<Control>", StrUtil.CaseIgnoreCmp) >= 0)) 181 k |= Keys.Control; 182 if((strKey.IndexOf(@"<Shft>", StrUtil.CaseIgnoreCmp) >= 0) || 183 (strKey.IndexOf(@"<Shift>", StrUtil.CaseIgnoreCmp) >= 0)) 184 k |= Keys.Shift; 185 186 string strKeyCode = strKey; 187 while(strKeyCode.IndexOf('<') >= 0) 188 { 189 int nStart = strKeyCode.IndexOf('<'); 190 int nEnd = strKeyCode.IndexOf('>'); 191 if((nStart < 0) || (nEnd < 0) || (nEnd <= nStart)) { Debug.Assert(false); break; } 192 193 strKeyCode = strKeyCode.Remove(nStart, nEnd - nStart + 1); 194 } 195 strKeyCode = strKeyCode.Trim(); 196 197 try { k |= (Keys)Enum.Parse(typeof(Keys), strKeyCode, true); } 198 catch(Exception) { Debug.Assert(false); } 199 200 return k; 201 } 202 203 private static string EggAccKeysToString(Keys k) 204 { 205 StringBuilder sb = new StringBuilder(); 206 207 if((k & Keys.Shift) != Keys.None) sb.Append(@"<Shift>"); 208 if((k & Keys.Control) != Keys.None) sb.Append(@"<Control>"); 209 if((k & Keys.Alt) != Keys.None) sb.Append(@"<Alt>"); 210 211 sb.Append((k & Keys.KeyCode).ToString()); 212 return sb.ToString(); 213 } */ 214 CheckCtrlAltA(Form fParent)215 internal static void CheckCtrlAltA(Form fParent) 216 { 217 try 218 { 219 if(!Program.Config.Integration.CheckHotKeys) return; 220 if(NativeLib.IsUnix()) return; 221 222 // Check for a conflict only in the very specific case of 223 // Ctrl+Alt+A; in all other cases we assume that the user 224 // is aware of a possible conflict and intentionally wants 225 // to override any system key combination 226 if(Program.Config.Integration.HotKeyGlobalAutoType != 227 (long)(Keys.Control | Keys.Alt | Keys.A)) return; 228 229 // Check for a conflict only on Polish systems; other 230 // languages typically don't use Ctrl+Alt+A frequently 231 // and a conflict warning would just be confusing for 232 // most users 233 IntPtr hKL = NativeMethods.GetKeyboardLayout(0); 234 ushort uLangID = (ushort)(hKL.ToInt64() & 0xFFFFL); 235 ushort uPriLangID = NativeMethods.GetPrimaryLangID(uLangID); 236 if(uPriLangID != NativeMethods.LANG_POLISH) return; 237 238 int vk = (int)Keys.A; 239 240 // We actually check for RAlt (which maps to Ctrl+Alt) 241 // instead of LCtrl+LAlt 242 byte[] pbState = new byte[256]; 243 pbState[NativeMethods.VK_CONTROL] = 0x80; 244 pbState[NativeMethods.VK_MENU] = 0x80; 245 pbState[NativeMethods.VK_RMENU] = 0x80; 246 pbState[NativeMethods.VK_NUMLOCK] = 0x01; // Toggled 247 // pbState[vk] = 0x80; 248 249 string strUni = NativeMethods.ToUnicode3(vk, pbState, IntPtr.Zero); 250 if(string.IsNullOrEmpty(strUni)) return; 251 if(strUni.EndsWith("a") || strUni.EndsWith("A")) return; 252 253 if(char.IsControl(strUni, 0)) { Debug.Assert(false); strUni = "?"; } 254 255 string str = KPRes.CtrlAltAConflict.Replace(@"{PARAM}", strUni) + 256 MessageService.NewParagraph + KPRes.CtrlAltAConflictHint; 257 258 VistaTaskDialog dlg = new VistaTaskDialog(); 259 dlg.AddButton((int)DialogResult.Cancel, KPRes.Ok, null); 260 dlg.CommandLinks = false; 261 dlg.Content = str; 262 dlg.DefaultButtonID = (int)DialogResult.Cancel; 263 dlg.MainInstruction = KPRes.KeyboardKeyCtrl + "+" + 264 KPRes.KeyboardKeyAlt + "+A - " + KPRes.Warning; 265 dlg.SetIcon(VtdIcon.Warning); 266 dlg.VerificationText = KPRes.DialogNoShowAgain; 267 dlg.WindowTitle = PwDefs.ShortProductName; 268 269 if(dlg.ShowDialog(fParent)) 270 { 271 if(dlg.ResultVerificationChecked) 272 Program.Config.Integration.CheckHotKeys = false; 273 } 274 else MessageService.ShowWarning(str); 275 } 276 catch(Exception) { Debug.Assert(false); } 277 } 278 HandleHotKeyIntoSelf(int wParam)279 internal static bool HandleHotKeyIntoSelf(int wParam) 280 { 281 try 282 { 283 OptionsForm f = (GlobalWindowManager.TopWindow as OptionsForm); 284 if(f == null) return false; 285 286 IntPtr h = NativeMethods.GetForegroundWindowHandle(); 287 if(h != f.Handle) return false; 288 289 HotKeyControlEx c = (f.ActiveControl as HotKeyControlEx); 290 if(c == null) return false; 291 292 Keys k; 293 if(!m_vRegKeys.TryGetValue(wParam, out k)) return false; 294 if(k == Keys.None) { Debug.Assert(false); return false; } 295 296 c.HotKey = k; 297 return true; 298 } 299 catch(Exception) { Debug.Assert(false); } 300 301 return false; 302 } 303 } 304 } 305