Fix a global hotkey issues in CMD, which will hang Wox on init.

This commit is contained in:
qianlifeng 2015-01-08 22:49:42 +08:00
parent 288be8dd71
commit 220ac2fa2d
15 changed files with 148 additions and 153 deletions

View File

@ -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);

View File

@ -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("\\"))

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -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;

View File

@ -81,6 +81,9 @@
<None Include="Images\program.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="Images\cmd.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<Content Include="Languages\en.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>

View File

@ -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
});
}
})
;
});
}
}

View File

@ -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
{
/// <summary>
/// Key down
/// </summary>
WM_KEYDOWN = 256,
/// <summary>
/// Key up
/// </summary>
WM_KEYUP = 257,
/// <summary>
/// System key up
/// </summary>
WM_SYSKEYUP = 261,
/// <summary>
/// System key down
/// </summary>
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;
}
/// <summary>
/// Listens keyboard globally.
/// <remarks>Uses WH_KEYBOARD_LL.</remarks>
/// </summary>
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;

View File

@ -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);
}
}

View File

@ -0,0 +1,25 @@
namespace Wox.Infrastructure.Hotkey
{
public enum KeyEvent:int
{
/// <summary>
/// Key down
/// </summary>
WM_KEYDOWN = 256,
/// <summary>
/// Key up
/// </summary>
WM_KEYUP = 257,
/// <summary>
/// System key up
/// </summary>
WM_SYSKEYUP = 261,
/// <summary>
/// System key down
/// </summary>
WM_SYSKEYDOWN = 260
}
}

View File

@ -59,6 +59,8 @@
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="Hotkey\InterceptKeys.cs" />
<Compile Include="Hotkey\KeyEvent.cs" />
<Compile Include="Logger\Log.cs" />
<Compile Include="PeHeaderReader.cs" />
<Compile Include="Storage\BinaryStorage.cs" />

View File

@ -8,6 +8,15 @@ namespace Wox.Plugin
{
public delegate void WoxKeyDownEventHandler(object sender, WoxKeyDownEventArgs e);
/// <summary>
/// Global keyboard events
/// </summary>
/// <param name="keyevent">WM_KEYDOWN = 256,WM_KEYUP = 257,WM_SYSKEYUP = 261,WM_SYSKEYDOWN = 260</param>
/// <param name="vkcode"></param>
/// <param name="state"></param>
/// <returns>return true to continue handling, return false to intercept system handling</returns>
public delegate bool WoxGlobalKeyboardEventHandler(int keyevent, int vkcode, SpecialKeyState state);
public class WoxKeyDownEventArgs
{
public string Query { get; set; }

View File

@ -41,5 +41,7 @@ namespace Wox.Plugin
List<PluginPair> GetAllPlugins();
event WoxKeyDownEventHandler BackKeyDownEvent;
event WoxGlobalKeyboardEventHandler GlobalKeyboardEvent;
}
}

View File

@ -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";

View File

@ -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<Result> waitShowResultList = new List<Result>();
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<Result> 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<Result> list)
private void OnUpdateResultView(List<Result> 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]);

View File

@ -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)
}
});