diff --git a/Plugins/Wox.Plugin.CMD/CMD.cs b/Plugins/Wox.Plugin.CMD/CMD.cs index 7cd9fe2f5b..993a5795a1 100644 --- a/Plugins/Wox.Plugin.CMD/CMD.cs +++ b/Plugins/Wox.Plugin.CMD/CMD.cs @@ -13,7 +13,6 @@ namespace Wox.Plugin.CMD { public class CMD : IPlugin, ISettingProvider,IPluginI18n { - private readonly GlobalHotkey globalHotkey = new GlobalHotkey(); private PluginInitContext context; private bool WinRStroked; private readonly KeyboardSimulator keyboardSimulator = new KeyboardSimulator(new InputSimulator()); @@ -174,20 +173,20 @@ namespace Wox.Plugin.CMD public void Init(PluginInitContext context) { this.context = context; - globalHotkey.hookedKeyboardCallback += KListener_hookedKeyboardCallback; + context.API.GlobalKeyboardEvent += API_GlobalKeyboardEvent; } - private bool KListener_hookedKeyboardCallback(KeyEvent keyevent, int vkcode, SpecialKeyState state) + bool API_GlobalKeyboardEvent(int keyevent, int vkcode, SpecialKeyState state) { if (CMDStorage.Instance.ReplaceWinR) { - if (keyevent == KeyEvent.WM_KEYDOWN && vkcode == (int)Keys.R && state.WinPressed) + if (keyevent == (int)KeyEvent.WM_KEYDOWN && vkcode == (int)Keys.R && state.WinPressed) { WinRStroked = true; OnWinRPressed(); return false; } - if (keyevent == KeyEvent.WM_KEYUP && WinRStroked && vkcode == (int)Keys.LWin) + if (keyevent == (int)KeyEvent.WM_KEYUP && WinRStroked && vkcode == (int)Keys.LWin) { WinRStroked = false; keyboardSimulator.ModifiedKeyStroke(VirtualKeyCode.LWIN, VirtualKeyCode.CONTROL); diff --git a/Plugins/Wox.Plugin.Folder/FolderPlugin.cs b/Plugins/Wox.Plugin.Folder/FolderPlugin.cs index 809e90f9fb..0d50ce0ca0 100644 --- a/Plugins/Wox.Plugin.Folder/FolderPlugin.cs +++ b/Plugins/Wox.Plugin.Folder/FolderPlugin.cs @@ -82,7 +82,7 @@ namespace Wox.Plugin.Folder } }).ToList(); - if (!driverNames.Any(input.StartsWith)) + if (driverNames != null && !driverNames.Any(input.StartsWith)) return results; if (!input.EndsWith("\\")) diff --git a/Plugins/Wox.Plugin.Program/Images/cmd.png b/Plugins/Wox.Plugin.Program/Images/cmd.png new file mode 100644 index 0000000000..4e4ca09443 Binary files /dev/null and b/Plugins/Wox.Plugin.Program/Images/cmd.png differ diff --git a/Plugins/Wox.Plugin.Program/Programs.cs b/Plugins/Wox.Plugin.Program/Programs.cs index afcd078a13..9c4d2d423d 100644 --- a/Plugins/Wox.Plugin.Program/Programs.cs +++ b/Plugins/Wox.Plugin.Program/Programs.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; +using System.Threading; using System.Windows; using Wox.Infrastructure; using Wox.Plugin.Program.ProgramSources; diff --git a/Plugins/Wox.Plugin.Program/Wox.Plugin.Program.csproj b/Plugins/Wox.Plugin.Program/Wox.Plugin.Program.csproj index 06c57a2cfb..5c24ffab52 100644 --- a/Plugins/Wox.Plugin.Program/Wox.Plugin.Program.csproj +++ b/Plugins/Wox.Plugin.Program/Wox.Plugin.Program.csproj @@ -81,6 +81,9 @@ PreserveNewest + + PreserveNewest + MSBuild:Compile Designer diff --git a/Wox.Core/Plugin/PluginManager.cs b/Wox.Core/Plugin/PluginManager.cs index 8620751f22..4ea7f5ebe8 100644 --- a/Wox.Core/Plugin/PluginManager.cs +++ b/Wox.Core/Plugin/PluginManager.cs @@ -100,7 +100,7 @@ namespace Wox.Core.Plugin PluginPair pair = pluginPair; ThreadPool.QueueUserWorkItem(o => { - using (new Timeit("Init Plugin: " + pair.Metadata.Name)) + using (new Timeit(string.Format("Init {0}", pair.Metadata.Name))) { pair.Plugin.Init(new PluginInitContext() { @@ -109,8 +109,7 @@ namespace Wox.Core.Plugin API = API }); } - }) - ; + }); } } diff --git a/Wox.Infrastructure/Hotkey/GlobalHotkey.cs b/Wox.Infrastructure/Hotkey/GlobalHotkey.cs index 8a6f31323b..d07b5180db 100644 --- a/Wox.Infrastructure/Hotkey/GlobalHotkey.cs +++ b/Wox.Infrastructure/Hotkey/GlobalHotkey.cs @@ -1,114 +1,17 @@ using System; -using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Wox.Plugin; namespace Wox.Infrastructure.Hotkey { - public enum KeyEvent : int - { - /// - /// Key down - /// - WM_KEYDOWN = 256, - - /// - /// Key up - /// - WM_KEYUP = 257, - - /// - /// System key up - /// - WM_SYSKEYUP = 261, - - /// - /// System key down - /// - WM_SYSKEYDOWN = 260 - } - - public static class InterceptKeys - { - public delegate IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam); - - private static int WH_KEYBOARD_LL = 13; - - public static IntPtr SetHook(LowLevelKeyboardProc proc) - { - using (Process curProcess = Process.GetCurrentProcess()) - using (ProcessModule curModule = curProcess.MainModule) - { - return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0); - } - } - - [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId); - - [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool UnhookWindowsHookEx(IntPtr hhk); - - [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, UIntPtr wParam, IntPtr lParam); - - [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] - public static extern IntPtr GetModuleHandle(string lpModuleName); - - [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] - public static extern short GetKeyState(int keyCode); - - [DllImport("user32.dll")] - internal static extern uint SendInput(uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize); - } - - [StructLayout(LayoutKind.Explicit)] - public struct INPUT - { - [FieldOffset(0)] - public Int32 type;//0-MOUSEINPUT;1-KEYBDINPUT;2-HARDWAREINPUT - [FieldOffset(4)] - public KEYBDINPUT ki; - [FieldOffset(4)] - public MOUSEINPUT mi; - [FieldOffset(4)] - public HARDWAREINPUT hi; - } - [StructLayout(LayoutKind.Sequential)] - public struct MOUSEINPUT - { - public Int32 dx; - public Int32 dy; - public Int32 mouseData; - public Int32 dwFlags; - public Int32 time; - public IntPtr dwExtraInfo; - } - [StructLayout(LayoutKind.Sequential)] - public struct KEYBDINPUT - { - public Int16 wVk; - public Int16 wScan; - public Int32 dwFlags; - public Int32 time; - public IntPtr dwExtraInfo; - } - [StructLayout(LayoutKind.Sequential)] - public struct HARDWAREINPUT - { - public Int32 uMsg; - public Int16 wParamL; - public Int16 wParamH; - } - /// /// Listens keyboard globally. /// Uses WH_KEYBOARD_LL. /// public class GlobalHotkey : IDisposable { + private static GlobalHotkey instance; private InterceptKeys.LowLevelKeyboardProc hookedLowLevelKeyboardProc; private IntPtr hookId = IntPtr.Zero; public delegate bool KeyboardCallback(KeyEvent keyEvent, int vkCode, SpecialKeyState state); @@ -120,7 +23,19 @@ namespace Wox.Infrastructure.Hotkey private const int VK_ALT = 0x12; private const int VK_WIN = 91; - public GlobalHotkey() + public static GlobalHotkey Instance + { + get + { + if (instance == null) + { + instance = new GlobalHotkey(); + } + return instance; + } + } + + private GlobalHotkey() { // We have to store the LowLevelKeyboardProc, so that it is not garbage collected runtime hookedLowLevelKeyboardProc = LowLevelKeyboardProc; diff --git a/Wox.Infrastructure/Hotkey/InterceptKeys.cs b/Wox.Infrastructure/Hotkey/InterceptKeys.cs new file mode 100644 index 0000000000..ef8dd576df --- /dev/null +++ b/Wox.Infrastructure/Hotkey/InterceptKeys.cs @@ -0,0 +1,38 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Wox.Infrastructure.Hotkey +{ + internal static class InterceptKeys + { + public delegate IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam); + + private const int WH_KEYBOARD_LL = 13; + + public static IntPtr SetHook(LowLevelKeyboardProc proc) + { + using (Process curProcess = Process.GetCurrentProcess()) + using (ProcessModule curModule = curProcess.MainModule) + { + return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0); + } + } + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool UnhookWindowsHookEx(IntPtr hhk); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, UIntPtr wParam, IntPtr lParam); + + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern IntPtr GetModuleHandle(string lpModuleName); + + [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true, CallingConvention = CallingConvention.Winapi)] + public static extern short GetKeyState(int keyCode); + } +} \ No newline at end of file diff --git a/Wox.Infrastructure/Hotkey/KeyEvent.cs b/Wox.Infrastructure/Hotkey/KeyEvent.cs new file mode 100644 index 0000000000..f1b6eefd0c --- /dev/null +++ b/Wox.Infrastructure/Hotkey/KeyEvent.cs @@ -0,0 +1,25 @@ +namespace Wox.Infrastructure.Hotkey +{ + public enum KeyEvent:int + { + /// + /// Key down + /// + WM_KEYDOWN = 256, + + /// + /// Key up + /// + WM_KEYUP = 257, + + /// + /// System key up + /// + WM_SYSKEYUP = 261, + + /// + /// System key down + /// + WM_SYSKEYDOWN = 260 + } +} \ No newline at end of file diff --git a/Wox.Infrastructure/Wox.Infrastructure.csproj b/Wox.Infrastructure/Wox.Infrastructure.csproj index 4c23af6316..a2b334b077 100644 --- a/Wox.Infrastructure/Wox.Infrastructure.csproj +++ b/Wox.Infrastructure/Wox.Infrastructure.csproj @@ -59,6 +59,8 @@ + + diff --git a/Wox.Plugin/EventHandler.cs b/Wox.Plugin/EventHandler.cs index 0fd8461deb..f3ef7e2e2d 100644 --- a/Wox.Plugin/EventHandler.cs +++ b/Wox.Plugin/EventHandler.cs @@ -8,6 +8,15 @@ namespace Wox.Plugin { public delegate void WoxKeyDownEventHandler(object sender, WoxKeyDownEventArgs e); + /// + /// Global keyboard events + /// + /// WM_KEYDOWN = 256,WM_KEYUP = 257,WM_SYSKEYUP = 261,WM_SYSKEYDOWN = 260 + /// + /// + /// return true to continue handling, return false to intercept system handling + public delegate bool WoxGlobalKeyboardEventHandler(int keyevent, int vkcode, SpecialKeyState state); + public class WoxKeyDownEventArgs { public string Query { get; set; } diff --git a/Wox.Plugin/IPublicAPI.cs b/Wox.Plugin/IPublicAPI.cs index 49279d7900..231faf4a7f 100644 --- a/Wox.Plugin/IPublicAPI.cs +++ b/Wox.Plugin/IPublicAPI.cs @@ -41,5 +41,7 @@ namespace Wox.Plugin List GetAllPlugins(); event WoxKeyDownEventHandler BackKeyDownEvent; + + event WoxGlobalKeyboardEventHandler GlobalKeyboardEvent; } } diff --git a/Wox/HotkeyControl.xaml.cs b/Wox/HotkeyControl.xaml.cs index e1650d197b..1725f64019 100644 --- a/Wox/HotkeyControl.xaml.cs +++ b/Wox/HotkeyControl.xaml.cs @@ -43,7 +43,7 @@ namespace Wox Key key = (e.Key == Key.System ? e.SystemKey : e.Key); string text = string.Empty; - SpecialKeyState specialKeyState = new GlobalHotkey().CheckModifiers(); + SpecialKeyState specialKeyState = GlobalHotkey.Instance.CheckModifiers(); if (specialKeyState.AltPressed) { text += "Alt"; diff --git a/Wox/MainWindow.xaml.cs b/Wox/MainWindow.xaml.cs index ed76bf6351..54061baf14 100644 --- a/Wox/MainWindow.xaml.cs +++ b/Wox/MainWindow.xaml.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; -using System.IO; +using System.Drawing; using System.Linq; +using System.Net; using System.Threading; using System.Windows; using System.Windows.Controls; @@ -10,8 +12,6 @@ using System.Windows.Forms; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Media.Animation; -using WindowsInput; -using WindowsInput.Native; using NHotkey; using NHotkey.Wpf; using Wox.Core.i18n; @@ -21,25 +21,18 @@ using Wox.Core.UserSettings; using Wox.Helper; using Wox.Infrastructure; using Wox.Infrastructure.Hotkey; -using Wox.Infrastructure.Storage; using Wox.Plugin; using Wox.Storage; using Wox.Update; -using Application = System.Windows.Application; using Brushes = System.Windows.Media.Brushes; using Color = System.Windows.Media.Color; using ContextMenu = System.Windows.Forms.ContextMenu; +using DataFormats = System.Windows.DataFormats; using DragEventArgs = System.Windows.DragEventArgs; -using FontFamily = System.Windows.Media.FontFamily; using KeyEventArgs = System.Windows.Input.KeyEventArgs; using MenuItem = System.Windows.Forms.MenuItem; using MessageBox = System.Windows.MessageBox; -using MouseButton = System.Windows.Input.MouseButton; -using Path = System.IO.Path; -using Rectangle = System.Drawing.Rectangle; -using TextBox = System.Windows.Controls.TextBox; using ToolTip = System.Windows.Controls.ToolTip; -using Wox.Infrastructure.Logger; namespace Wox { @@ -48,10 +41,6 @@ namespace Wox #region Properties - private static readonly object locker = new object(); - public static bool initialized = false; - - private static readonly List waitShowResultList = new List(); private readonly Storyboard progressBarStoryboard = new Storyboard(); private NotifyIcon notifyIcon; private bool queryHasReturn; @@ -59,7 +48,6 @@ namespace Wox private ToolTip toolTip = new ToolTip(); private bool ignoreTextChange = false; - private readonly GlobalHotkey globalHotkey = new GlobalHotkey(); #endregion @@ -143,6 +131,7 @@ namespace Wox } public event WoxKeyDownEventHandler BackKeyDownEvent; + public event WoxGlobalKeyboardEventHandler GlobalKeyboardEvent; public void PushResults(Query query, PluginMetadata plugin, List results) { @@ -166,26 +155,27 @@ namespace Wox public MainWindow() { InitializeComponent(); - + ThreadPool.SetMaxThreads(30, 10); + ThreadPool.SetMinThreads(10, 5); if (UserSettingStorage.Instance.OpacityMode == OpacityMode.LayeredWindow) + { this.AllowsTransparency = true; + } - System.Net.WebRequest.RegisterPrefix("data", new DataWebRequestFactory()); - + WebRequest.RegisterPrefix("data", new DataWebRequestFactory()); + GlobalHotkey.Instance.hookedKeyboardCallback += KListener_hookedKeyboardCallback; progressBar.ToolTip = toolTip; InitialTray(); pnlResult.LeftMouseClickEvent += SelectResult; pnlContextMenu.LeftMouseClickEvent += SelectResult; pnlResult.RightMouseClickEvent += pnlResult_RightMouseClickEvent; - ThreadPool.SetMaxThreads(30, 10); ThemeManager.Theme.ChangeTheme(UserSettingStorage.Instance.Theme); InternationalizationManager.Internationalization.ChangeLanguage(UserSettingStorage.Instance.Language); SetHotkey(UserSettingStorage.Instance.Hotkey, OnHotkey); SetCustomPluginHotkey(); - Closing += MainWindow_Closing; //since MainWIndow implement IPublicAPI, so we need to finish ctor MainWindow object before //PublicAPI invoke in plugin init methods. E.g FolderPlugin @@ -199,7 +189,16 @@ namespace Wox Thread.Sleep(50); PreLoadImages(); }); - ThreadPool.QueueUserWorkItem(o => CheckUpdate()); + CheckUpdate(); + } + + private bool KListener_hookedKeyboardCallback(KeyEvent keyevent, int vkcode, SpecialKeyState state) + { + if (GlobalKeyboardEvent != null) + { + return GlobalKeyboardEvent((int)keyevent, vkcode, state); + } + return true; } private void PreLoadImages() @@ -214,18 +213,21 @@ namespace Wox void CheckUpdate() { - Release release = new UpdateChecker().CheckUpgrade(); - if (release != null && !UserSettingStorage.Instance.DontPromptUpdateMsg) + ThreadPool.QueueUserWorkItem(o => { - Dispatcher.Invoke(new Action(() => + Release release = new UpdateChecker().CheckUpgrade(); + if (release != null && !UserSettingStorage.Instance.DontPromptUpdateMsg) { - NewVersionWindow newVersinoWindow = new NewVersionWindow(); - newVersinoWindow.Show(); - })); - } + Dispatcher.Invoke(new Action(() => + { + NewVersionWindow newVersinoWindow = new NewVersionWindow(); + newVersinoWindow.Show(); + })); + } + }); } - void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e) + void MainWindow_Closing(object sender, CancelEventArgs e) { UserSettingStorage.Instance.WindowLeft = Left; UserSettingStorage.Instance.WindowTop = Top; @@ -370,7 +372,7 @@ namespace Wox } }, TimeSpan.FromSeconds(0), lastQuery); } - }, TimeSpan.FromMilliseconds(ShouldNotDelayQuery ? 0 : 150)); + }, TimeSpan.FromMilliseconds(ShouldNotDelayQuery ? 0 : 200)); } private void BackToResultMode() @@ -482,7 +484,7 @@ namespace Wox break; case Key.Tab: - if (globalHotkey.CheckModifiers().ShiftPressed) + if (GlobalHotkey.Instance.CheckModifiers().ShiftPressed) { SelectPrevItem(); } @@ -534,7 +536,7 @@ namespace Wox case Key.Enter: Result activeResult = GetActiveResult(); - if (globalHotkey.CheckModifiers().ShiftPressed) + if (GlobalHotkey.Instance.CheckModifiers().ShiftPressed) { ShowContextMenu(activeResult); } @@ -600,7 +602,7 @@ namespace Wox { bool hideWindow = result.Action(new ActionContext() { - SpecialKeyState = globalHotkey.CheckModifiers() + SpecialKeyState = GlobalHotkey.Instance.CheckModifiers() }); if (hideWindow) { @@ -611,7 +613,7 @@ namespace Wox } } - public void OnUpdateResultView(List list) + private void OnUpdateResultView(List list) { queryHasReturn = true; progressBar.Dispatcher.Invoke(new Action(StopProgress)); @@ -663,10 +665,10 @@ namespace Wox private void MainWindow_OnDrop(object sender, DragEventArgs e) { - if (e.Data.GetDataPresent(System.Windows.DataFormats.FileDrop)) + if (e.Data.GetDataPresent(DataFormats.FileDrop)) { // Note that you can have more than one file. - string[] files = (string[])e.Data.GetData(System.Windows.DataFormats.FileDrop); + string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); if (files[0].ToLower().EndsWith(".wox")) { PluginManager.InstallPlugin(files[0]); diff --git a/Wox/SettingWindow.xaml.cs b/Wox/SettingWindow.xaml.cs index 56f5f3435c..b7c1ca520f 100644 --- a/Wox/SettingWindow.xaml.cs +++ b/Wox/SettingWindow.xaml.cs @@ -105,48 +105,48 @@ namespace Wox { Title = "Wox is an effective launcher for windows", SubTitle = "Wox provide bundles of features let you access infomations quickly.", - IcoPath = "Images/work.png", + IcoPath = "Images/app.png", PluginDirectory = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath) }, new Result() { Title = "Search applications", SubTitle = "Search applications, files (via everything plugin) and browser bookmarks", - IcoPath = "Images/work.png", + IcoPath = "Images/app.png", PluginDirectory = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath) }, new Result() { Title = "Search web contents with shortcuts", SubTitle = "e.g. search google with g keyword or youtube keyword)", - IcoPath = "Images/work.png", + IcoPath = "Images/app.png", PluginDirectory = Path.GetDirectoryName(Application.ExecutablePath) }, new Result() { Title = "clipboard history ", - IcoPath = "Images/work.png", + IcoPath = "Images/app.png", PluginDirectory = Path.GetDirectoryName(Application.ExecutablePath) }, new Result() { Title = "Themes support", SubTitle = "get more themes from http://www.getwox.com/theme", - IcoPath = "Images/work.png", + IcoPath = "Images/app.png", PluginDirectory = Path.GetDirectoryName(Application.ExecutablePath) }, new Result() { Title = "Plugins support", SubTitle = "get more plugins from http://www.getwox.com/plugin", - IcoPath = "Images/work.png", + IcoPath = "Images/app.png", PluginDirectory = Path.GetDirectoryName(Application.ExecutablePath) }, new Result() { Title = "Wox is an open-source software", SubTitle = "Wox benefits from the open-source community a lot", - IcoPath = "Images/work.png", + IcoPath = "Images/app.png", PluginDirectory = Path.GetDirectoryName(Application.ExecutablePath) } });