The main composer class. It gets input from the keyboard hook, and acts depending on the global configuration and current keyboard state.
예제 #1
0
        private static void ComposerStateChanged(object sender, EventArgs e)
        {
            m_tray_icon.Icon = Composer.IsDisabled()  ? Properties.Resources.IconDisabled
                             : Composer.IsComposing() ? Properties.Resources.IconActive
                                                      : Properties.Resources.IconNormal;
            m_tray_icon.Text = Composer.IsDisabled()
                              ? i18n.Text.DisabledToolTip
                              : String.Format(i18n.Text.TrayToolTip,
                                              Settings.ComposeKey.Value.FriendlyName,
                                              Settings.GetSequenceCount(),
                                              Program.Version);

            m_disable_item.Checked = Composer.IsDisabled();
        }
예제 #2
0
        private static int OnKey(HC nCode, WM wParam, IntPtr lParam)
        {
            bool is_key = (wParam == WM.KEYDOWN || wParam == WM.SYSKEYDOWN ||
                           wParam == WM.KEYUP || wParam == WM.SYSKEYUP);

            if (m_duplicate != 0)
            {
                // Do nothing. We can only get here if a key is pressed during
                // the very short time where we have two hooks installed, i.e.
                // practically never, but it’s better to handle this properly.
            }
            else if (nCode == HC.ACTION && is_key)
            {
                // Retrieve key event data from native structure
                var data = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam,
                                                                   typeof(KBDLLHOOKSTRUCT));
                bool is_injected = (data.flags & LLKHF.INJECTED) != 0;
                bool accept      = !is_injected || (Settings.AllowInjected.Value && m_recursive == 0);

                Logger.Debug("{0}{1}: OnKey(HC.{2}, WM.{3}, [vk:0x{4:X02} ({7}) sc:0x{5:X02} flags:{6}])",
                             accept ? "" : "Ignored ", is_injected ? "Injected Event" : "Event",
                             nCode, wParam, (int)data.vk, (int)data.sc, data.flags, new Key(data.vk));

                if (accept)
                {
                    ++m_recursive;
                    bool processed = Composer.OnKey(wParam, data.vk, data.sc, data.flags);
                    --m_recursive;

                    if (processed)
                    {
                        return(-1); // Do not process further: that key was for us.
                    }
                }
            }
            else
            {
                Logger.Debug("Ignored Event: OnKey({0}, {1})", nCode, wParam);
            }

            // Call next hook but guard against re-doing our own work in case we
            // were installed twice.
            ++m_duplicate;
            int ret = NativeMethods.CallNextHookEx(m_hook, nCode, wParam, lParam);

            --m_duplicate;

            return(ret);
        }
예제 #3
0
        static void Main(string[] args)
        {
            // Some commandline flags just trigger a message broadcast
            var command_flags = new Dictionary <string, MenuCommand>()
            {
                { "-sequences", MenuCommand.ShowSequences },
                { "-settings", MenuCommand.ShowOptions },
            };

            foreach (var arg in args)
            {
                if (command_flags.TryGetValue(arg, out var cmd))
                {
                    NativeMethods.PostMessage(HWND.BROADCAST, WM_WINCOMPOSE.OPEN, (int)cmd, 0);
                    return;
                }
            }

            // Do this before Composer.Init() because of the Disabled setting
            Settings.LoadConfig();

            Composer.Init();
            Settings.LoadSequences();
            Metadata.LoadDB();
            KeyboardHook.Init();
            Updater.Init();

            Settings.StartWatchConfigFile();

            try
            {
                var app  = new Application();
                var icon = new SysTrayIcon();
                app.Exit += (o, e) => icon.Dispose();
                app.Run();
            }
            finally
            {
                Settings.StopWatchConfigFile();
                Updater.Fini();
                KeyboardHook.Fini();
                Settings.SaveConfig();
                Metadata.SaveDB();
                Composer.Fini();
                Updater.Fini();
            }
        }
예제 #4
0
        private static string GetCurrentToolTip()
        {
            string ret = i18n.Text.DisabledToolTip;

            if (!Composer.IsDisabled())
            {
                ret = string.Format(i18n.Text.TrayToolTip,
                                    Settings.ComposeKeys.Value.FriendlyName,
                                    Settings.SequenceCount,
                                    Settings.Version);
            }

            if (Updater.HasNewerVersion())
            {
                ret += "\n" + i18n.Text.UpdatesToolTip;
            }

            return(ret);
        }
예제 #5
0
        private static void SysTrayUpdateCallback(object sender, EventArgs e)
        {
            m_tray_icon.Icon = GetCurrentIcon();

            // XXX: we cannot directly set m_tray_icon.Text because it has an
            // erroneous 64-character limitation (the underlying framework has
            // the correct 128-char limitation). So instead we use this hack,
            // taken from http://stackoverflow.com/a/580264/111461
            Type         t      = typeof(WinForms.NotifyIcon);
            BindingFlags hidden = BindingFlags.NonPublic | BindingFlags.Instance;

            t.GetField("text", hidden).SetValue(m_tray_icon, GetCurrentToolTip());
            if ((bool)t.GetField("added", hidden).GetValue(m_tray_icon))
            {
                t.GetMethod("UpdateIcon", hidden).Invoke(m_tray_icon, new object[] { true });
            }

            m_disable_item.Checked = Composer.IsDisabled();
        }
예제 #6
0
        static void Main()
        {
            // Do this before Composer.Init() because of the Disabled setting
            Settings.LoadConfig();

            Composer.Init();
            Settings.LoadSequences();
            Updater.Init();

            Settings.StartWatchConfigFile();

            try
            {
                WinForms.Application.EnableVisualStyles();
                WinForms.Application.SetCompatibleTextRenderingDefault(false);

                // Must call this after SetCompatibleTextRenderingDefault()
                // because it uses a WinForms timer which seems to open a
                // hidden window. The reason we use a WinForms timer is so that
                // the hook is installed from the main thread.
                KeyboardHook.Init();

                using (SysTrayIcon icon = new SysTrayIcon())
                {
                    WinForms.Application.Run();
                }
            }
            finally
            {
                Settings.StopWatchConfigFile();
                Updater.Fini();
                KeyboardHook.Fini();
                Settings.SaveConfig();
                Composer.Fini();
                Updater.Fini();
            }
        }
예제 #7
0
        private static int OnKey(HC nCode, WM wParam, IntPtr lParam)
        {
            if (nCode == HC.ACTION)
            {
                // Retrieve event data from native structure
                var data = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam,
                                                                   typeof(KBDLLHOOKSTRUCT));

                bool is_key = (wParam == WM.KEYDOWN || wParam == WM.SYSKEYDOWN ||
                               wParam == WM.KEYUP || wParam == WM.SYSKEYUP);
                bool is_injected = (data.flags & LLKHF.INJECTED) != 0;

                if (is_key && !is_injected)
                {
                    if (Composer.OnKey(wParam, data.vk, data.sc, data.flags))
                    {
                        // Do not process further: that key was for us.
                        return(-1);
                    }
                }
            }

            return(NativeMethods.CallNextHookEx(m_hook, nCode, wParam, lParam));
        }
예제 #8
0
        private void OnMenuItemClicked(object parameter)
        {
            switch (parameter as MenuCommand?)
            {
            case MenuCommand.ShowSequences:
                if (m_sequencewindow == null)
                {
                    m_sequencewindow = new SequenceWindow();
                    WinForms.Integration.ElementHost.EnableModelessKeyboardInterop(m_sequencewindow);
                }
                m_sequencewindow.Show();
                m_sequencewindow.Activate();
                break;

            case MenuCommand.ShowOptions:
                if (m_optionswindow == null)
                {
                    m_optionswindow = new SettingsWindow();
                    WinForms.Integration.ElementHost.EnableModelessKeyboardInterop(m_optionswindow);
                }
                m_optionswindow.Show();
                m_optionswindow.Activate();
                break;

            case MenuCommand.DebugWindow:
                if (m_debugwindow == null)
                {
                    m_debugwindow = new DebugWindow();
                }
                m_debugwindow.Show();
                m_debugwindow.Activate();
                break;

            case MenuCommand.About:
                var about_box = new AboutBox();
                about_box.ShowDialog();
                break;

            case MenuCommand.Download:
                var url = Settings.IsInstalled() ? Updater.Get("Installer")
                                                     : Updater.Get("Portable");
                System.Diagnostics.Process.Start(url);
                break;

            case MenuCommand.VisitWebsite:
                System.Diagnostics.Process.Start("http://wincompose.info/");
                break;

            case MenuCommand.Disable:
                if (Composer.IsDisabled)
                {
                    m_control.TriggerDisableEvent();
                }
                Composer.ToggleDisabled();
                SysTrayUpdateCallback(null, new EventArgs());
                break;

            case MenuCommand.Restart:
                // FIXME: there might be more cleanup to do here; but it’s probably
                // not worth it, because restarting the app is a hack and whatever
                // reason the user may have, it’s because of a bug or a limitation
                // in WinCompose that we need to fix.
                m_icon.Visible = false;
                WinForms.Application.Restart();
                Environment.Exit(0);
                break;

            case MenuCommand.Exit:
                WinForms.Application.Exit();
                break;
            }
        }
예제 #9
0
        private void OnMenuItemClicked(object parameter)
        {
            switch (parameter as MenuCommand?)
            {
            case MenuCommand.ShowSequences:
                m_sequencewindow = m_sequencewindow ?? new SequenceWindow();
                m_sequencewindow.Show();
                m_sequencewindow.Activate();
                break;

            case MenuCommand.ShowOptions:
                m_optionswindow = m_optionswindow ?? new SettingsWindow();
                m_optionswindow.Show();
                m_optionswindow.Activate();
                break;

            case MenuCommand.DebugWindow:
                m_debugwindow = m_debugwindow ?? new DebugWindow();
                m_debugwindow.Show();
                m_debugwindow.Activate();
                break;

            case MenuCommand.About:
                m_about_box = m_about_box ?? new AboutBox();
                m_about_box.Show();
                m_about_box.Activate();
                break;

            case MenuCommand.Download:
                var url = Settings.IsInstalled() ? Updater.Get("Installer")
                                                     : Updater.Get("Portable");
                System.Diagnostics.Process.Start(url);
                break;

            case MenuCommand.VisitWebsite:
                System.Diagnostics.Process.Start("http://wincompose.info/");
                break;

            case MenuCommand.DonationPage:
                System.Diagnostics.Process.Start("http://wincompose.info/donate/");
                break;

            case MenuCommand.Disable:
                if (Composer.IsDisabled)
                {
                    Application.RemoteControl.BroadcastDisableEvent();
                }
                Composer.ToggleDisabled();
                break;

            case MenuCommand.Restart:
                // FIXME: there might be more cleanup to do here; but it’s probably
                // not worth it, because restarting the app is a hack and whatever
                // reason the user may have, it’s because of a bug or a limitation
                // in WinCompose that we need to fix.
                m_icon.Visible = false;
                Application.Current.Shutdown();
                WinForms.Application.Restart();
                Environment.Exit(0);
                break;

            case MenuCommand.Exit:
                Application.Current.Shutdown();
                break;
            }
        }
예제 #10
0
 private System.Drawing.Icon GetCurrentIcon()
 {
     return(GetIcon((Composer.IsDisabled() ?     0x1 : 0x0) |
                    (Composer.IsComposing() ?    0x2 : 0x0) |
                    (Updater.HasNewerVersion() ? 0x4 : 0x0)));
 }
예제 #11
0
        static void Main()
        {
            // Do this before Composer.Init() because of the Disabled setting
            Settings.LoadConfig();

            Composer.Init();
            Settings.LoadSequences();
            KeyboardHook.Init();
            Updater.Init();

            Settings.StartWatchConfigFile();

            try
            {
                WinForms.Application.EnableVisualStyles();
                WinForms.Application.SetCompatibleTextRenderingDefault(false);

                m_control = new RemoteControl();
                m_control.DisableEvent += OnDisableEvent;
                m_control.DisableEvent += SysTrayUpdateCallback;
                m_control.ExitEvent    += OnExitEvent;
                m_control.TriggerDisableEvent();

                m_tray_icon = new WinForms.NotifyIcon
                {
                    Visible = true,
                    //Icon = GetCurrentIcon(),
                    //Text = GetCurrentToolTip(),
                    ContextMenu = new WinForms.ContextMenu(new[]
                    {
                        new TitleMenuItem(),
                        new WinForms.MenuItem("-"),
                        new WinForms.MenuItem(i18n.Text.ShowSequences, ShowSequencesClicked),
                        new WinForms.MenuItem(i18n.Text.ShowOptions, ShowOptionsClicked),
                        m_help_item = /* Keep a reference on this entry */
                                      new WinForms.MenuItem(i18n.Text.Help, new[]
                        {
                            new WinForms.MenuItem(i18n.Text.About, AboutClicked),
                            new WinForms.MenuItem(i18n.Text.VisitWebsite, delegate(object o, EventArgs e) { System.Diagnostics.Process.Start("http://wincompose.info/"); }),
                            m_download_item = /* Keep a reference on this entry */
                                              new WinForms.MenuItem("", DownloadClicked)
                            {
                                Visible = false
                            },
                        }),
                        new WinForms.MenuItem("-"),
                        m_disable_item = /* Keep a reference on this entry */
                                         new WinForms.MenuItem(i18n.Text.Disable, DisableClicked),
                        new WinForms.MenuItem(i18n.Text.Restart, RestartClicked),
                        new WinForms.MenuItem(i18n.Text.Exit, OnExitEvent),
                    })
                };
                m_tray_icon.DoubleClick += NotifyiconDoubleclicked;

                Composer.Changed += SysTrayUpdateCallback;
                Updater.Changed  += SysTrayUpdateCallback;
                SysTrayUpdateCallback(null, new EventArgs());

                Updater.Changed += UpdaterStateChanged;
                UpdaterStateChanged(null, new EventArgs());

                WinForms.Application.Run();
                m_tray_icon.Dispose();
            }
            finally
            {
                Composer.Changed       -= SysTrayUpdateCallback;
                Updater.Changed        -= SysTrayUpdateCallback;
                Updater.Changed        -= UpdaterStateChanged;
                m_control.DisableEvent -= OnDisableEvent;
                m_control.ExitEvent    -= OnExitEvent;

                Settings.StopWatchConfigFile();
                Updater.Fini();
                KeyboardHook.Fini();
                Settings.SaveConfig();
                Composer.Fini();
                Updater.Fini();
            }
        }
예제 #12
0
        private void OnCommand(object o)
        {
            switch (o as MenuCommand?)
            {
            case MenuCommand.ShowSequences:
                m_sequencewindow = m_sequencewindow ?? new SequenceWindow();
                m_sequencewindow.Show();
                m_sequencewindow.Activate();
                break;

            case MenuCommand.ShowOptions:
                m_optionswindow = m_optionswindow ?? new SettingsWindow();
                m_optionswindow.Show();
                m_optionswindow.Activate();
                break;

            case MenuCommand.DebugWindow:
                m_debugwindow = m_debugwindow ?? new DebugWindow();
                m_debugwindow.Show();
                m_debugwindow.Activate();
                break;

            case MenuCommand.About:
                m_about_box = m_about_box ?? new AboutBox();
                m_about_box.Show();
                m_about_box.Activate();
                break;

            case MenuCommand.Download:
                var url = Utils.IsInstalled ? Updater.Get("Installer")
                                                : Updater.Get("Portable");
                Process.Start(url);
                break;

            case MenuCommand.VisitWebsite:
                Process.Start("http://wincompose.info/");
                break;

            case MenuCommand.DonationPage:
                Process.Start("http://wincompose.info/donate/");
                break;

            case MenuCommand.Disable:
                if (Composer.IsDisabled)
                {
                    Application.RemoteControl.BroadcastDisableEvent();
                }
                Composer.ToggleDisabled();
                break;

            case MenuCommand.Restart:
                // FIXME: there might be more cleanup to do here; but it’s probably
                // not worth it, because restarting the app is a hack and whatever
                // reason the user may have, it’s because of a bug or a limitation
                // in WinCompose that we need to fix.
                Visibility = Visibility.Collapsed;
                Application.Current.Exit += (s, e) => Process.Start(Application.ResourceAssembly.Location);
                Application.Current.Shutdown();
                break;

            case MenuCommand.Exit:
                Application.Current.Shutdown();
                break;
            }
        }