1using System; 2using System.Drawing; 3using System.Runtime.InteropServices; 4using System.Threading; 5using System.Windows.Forms; 6using WindowCapture.UI; 7 8namespace WindowCapture.App 9{ 10 /// <summary>The launcher hub: a tray icon + a global hotkey (Ctrl+Alt+Space) that pops a 11 /// radial menu to start the separate apps. Re-running "--launcher" (or the launcher hotkey) 12 /// surfaces the wheel.</summary> 13 public class LauncherApp : ApplicationContext 14 { 15 private NotifyIcon tray; 16 private HotkeyWindow hotkeyWindow; 17 private LauncherForm wheel; 18 private EventWaitHandle showEvent; 19 private Thread showListener; 20 private volatile bool stopping; 21 22 public LauncherApp() 23 { 24 hotkeyWindow = new HotkeyWindow(); 25 hotkeyWindow.HotkeyPressed += ShowWheel; 26 27 var menu = new ContextMenuStrip(); 28 menu.Items.Add("Открыть меню (Ctrl+Alt+Space)", null, delegate { ShowWheel(); }); 29 menu.Items.Add("-"); 30 foreach (AppMode m in new[] { AppMode.Screenshot, AppMode.TextAssist, AppMode.Clipboard, AppMode.Soundpad, AppMode.Search }) 31 { 32 var mm = m; // capture 33 menu.Items.Add(AppModes.Title(mm), null, delegate { AppModes.Launch(mm); }); 34 } 35 menu.Items.Add("-"); 36 menu.Items.Add("Настройки", null, delegate { try { using (var d = new SettingsDialog()) d.ShowDialog(); } catch { } }); 37 menu.Items.Add("Выход", null, delegate { ExitThread(); }); 38 39 tray = new NotifyIcon 40 { 41 Icon = AppModes.CreateDiscIcon(Color.FromArgb(120, 170, 240)), 42 Text = "WindowCapture — Лаунчер (Ctrl+Alt+Space)", 43 Visible = true, 44 ContextMenuStrip = menu 45 }; 46 tray.MouseClick += delegate(object s, MouseEventArgs e) { if (e.Button == MouseButtons.Left) ShowWheel(); }; 47 48 SetupShowListener(); 49 } 50 51 private void SetupShowListener() 52 { 53 bool created; 54 showEvent = new EventWaitHandle(false, EventResetMode.AutoReset, AppModes.ShowEventName(AppMode.Launcher), out created); 55 showListener = new Thread(delegate () 56 { 57 while (!stopping) 58 { 59 try { if (showEvent.WaitOne(500) && !stopping && hotkeyWindow != null) hotkeyWindow.BeginInvoke(new Action(ShowWheel)); } 60 catch { } 61 } 62 }) { IsBackground = true }; 63 showListener.Start(); 64 } 65 66 private void ShowWheel() 67 { 68 if (wheel != null && !wheel.IsDisposed) { try { wheel.Activate(); } catch { } return; } 69 wheel = new LauncherForm(); 70 wheel.ItemChosen += delegate(AppMode m) { AppModes.Launch(m); }; 71 wheel.FormClosed += delegate { wheel = null; }; 72 wheel.Show(); 73 } 74 75 protected override void Dispose(bool disposing) 76 { 77 if (disposing) 78 { 79 stopping = true; 80 try { if (showEvent != null) showEvent.Set(); } catch { } 81 if (tray != null) { tray.Visible = false; tray.Dispose(); } 82 if (hotkeyWindow != null) hotkeyWindow.Dispose(); 83 if (wheel != null && !wheel.IsDisposed) wheel.Dispose(); 84 } 85 base.Dispose(disposing); 86 } 87 88 /// <summary>Invisible message-only-ish window that owns the global hotkey registration.</summary> 89 private class HotkeyWindow : Form 90 { 91 public event Action HotkeyPressed; 92 [DllImport("user32.dll")] private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk); 93 [DllImport("user32.dll")] private static extern bool UnregisterHotKey(IntPtr hWnd, int id); 94 private const uint MOD_ALT = 0x1, MOD_CONTROL = 0x2, MOD_NOREPEAT = 0x4000; 95 private const int WM_HOTKEY = 0x0312; 96 private const int HOTKEY_ID = 0xB001; 97 private bool registered; 98 99 public HotkeyWindow() 100 { 101 FormBorderStyle = FormBorderStyle.None; 102 ShowInTaskbar = false; 103 StartPosition = FormStartPosition.Manual; 104 Location = new Point(-2000, -2000); 105 Size = new Size(1, 1); 106 var force = Handle; // force handle creation 107 } 108 109 protected override void OnHandleCreated(EventArgs e) 110 { 111 base.OnHandleCreated(e); 112 try { registered = RegisterHotKey(Handle, HOTKEY_ID, MOD_CONTROL | MOD_ALT | MOD_NOREPEAT, 0x20 /*VK_SPACE*/); } 113 catch { registered = false; } 114 } 115 116 protected override void SetVisibleCore(bool value) { base.SetVisibleCore(false); } // never visible 117 118 protected override void WndProc(ref Message m) 119 { 120 if (m.Msg == WM_HOTKEY && m.WParam.ToInt32() == HOTKEY_ID) 121 { 122 var h = HotkeyPressed; 123 if (h != null) h(); 124 } 125 base.WndProc(ref m); 126 } 127 128 protected override void Dispose(bool disposing) 129 { 130 if (disposing && registered) { try { UnregisterHotKey(Handle, HOTKEY_ID); } catch { } } 131 base.Dispose(disposing); 132 } 133 } 134 } 135}