当我将可见值正确设置为 true 时,如何防止我的 C# winforms 应用程序窃取焦点?

发布于 2024-09-01 19:21:06 字数 617 浏览 5 评论 0原文

我有一个在后台运行的 C# winforms 应用程序,侦听按下的热键。当按下热键时,我的表单会短暂出现。该窗体始终运行,但设置为隐藏,直到我收到热键事件,此时我将visible属性设置为true。代码如下所示:

void hook_volumeDown(object sender, KeyPressedEventArgs e)
{
    this.Visible = true;
}

需要注意的是,该表单的最顶层属性设置为 true。

真正奇怪的是,在我的 C# 应用程序从另一个应用程序窃取焦点后,它再也不会这样做了。例如:我启动我的应用程序,然后启动一些全屏应用程序,例如 Team Fortress 2。然后我按下热键。 Team Fortress 2 最小化,我看到了我的形态。然而,然后我可以恢复 TF2,并再次按我想要的热键(达到所需的效果),并且 TF2 将保持焦点。

无论如何,我正在寻找一种方法来解决这个问题。我在这里发现了很多涉及类似问题的问题,但所有这些问题都与创建/启动新表单有关,而不是使现有表单可见(除非我错过了某些内容)。我可以在每次需要时重新设计应用程序以创建一个新表单,但这需要创建另一个始终不可见的表单,只是为了等待热键事件,所以我宁愿保持原样。

有什么想法吗?

I've got a C# winforms application that runs in the background, listening for hotkeys to be pressed. When a hotkey is pressed, my form makes a brief appearance. The form is always running, but set to hidden until I receive a hotkey event, at which time I set the visible property to true. The code looks like this:

void hook_volumeDown(object sender, KeyPressedEventArgs e)
{
    this.Visible = true;
}

It should be noted that the topmost property of this form is set to true.

The really odd part is, after my C# app has stolen focus from another application, it will never do it again. For example: I launch my app, then launch some fullscreep app like Team Fortress 2. Then I press my hotkey. Team Fortress 2 minimizes, and I see my form. Then, however, I can restore TF2, and press my hotkey again all I want (with the desired effect), and TF2 will remain focused.

At any rate, I'm looking for a way to fix this. I've found a lot of questions here covering similar problems, but all of them are related to creating/launching a new form, not making an existing one visible (unless I missed something). I could rework the application to create a new form every time I need one, but that would entail creating yet another form to be invisible all the time just to wait for hotkey events, so I'd rather leave it as it is.

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

毁我热情 2024-09-08 19:21:06

我认为您的问题与 Visible = true 在第一次调用和后续调用之间的行为不同有关。第一次调用visible并且还没有创建窗口句柄时,窗口是通过调用CreateWindowEx创建的,它有一些控制窗口行为的样式参数。我认为您需要确保窗口是使用 WS_EX_NOACTIVATE 样式创建的,您可以通过重写 CreateParams 来做到这一点。

其他要尝试的事情:

1) ShowWindow 函数(由 Visible = true 使用)在第一次调用时会忽略焦点参数(http://msdn.microsoft.com/en-us/library/ms633548%28VS.85%29.aspx)(如果程序提供) STARTUPINFO 结构。深入研究 Reflector 并找出 Form 类是否提供 STARTUPINFO 结构,如果是,如何操作它。

2) 表单有一个 ShowWithoutActivation 属性,可以被覆盖并设置为 true,您是否覆盖了该属性?

很抱歉“没有确切的答案”,但我希望这至少为您提供了进一步调查的一些起点。祝你好运。

I think you problem is related to the fact that Visible = true behaves differently between the first and subsequent calls. The first time visible is called and the window handle has not been created, the Window is created by calling CreateWindowEx which has some style parameters which controls how the window should behave. I think you need to make sure that the window is created with the style WS_EX_NOACTIVATE, which you can do by overriding CreateParams.

Other things to try out:

1) The ShowWindow function (used by Visible = true) ignores the focus parameter the first time it is called (http://msdn.microsoft.com/en-us/library/ms633548%28VS.85%29.aspx) if the program provides a STARTUPINFO structure. Dig into reflector and find out if the Form class provides a STARTUPINFO structure and if so, how to manipulate it.

2) The Form has a ShowWithoutActivation property than can be overriden and set to true, have you overriden this?

Sorry for the "no exact answer", but I hope this at least gives you some starting points for further investigation. Good luck.

我的奇迹 2024-09-08 19:21:06

看到在您的函数中使用 KeyPressedEventArgs 看起来确实很奇怪。热键可以通过调用RegisterHotKey() API函数来实现。当按下热键时,它会向您的窗口发送一条消息。这是一个在启动时不可见的窗体示例,当您按下热键时会弹出。在这种情况下按 Ctrl+Alt+U:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {
        private const int MYKEYID = 0;    // In case you want to register more than one...
        public Form1() {
            InitializeComponent();
            this.FormClosing += (s, args) => UnregisterHotKey(this.Handle, MYKEYID);
        }
        protected override void SetVisibleCore(bool value) {
            if (value && !this.IsHandleCreated) {
                this.CreateHandle();
                RegisterHotKey(this.Handle, MYKEYID, MOD_CONTROL + MOD_SHIFT, Keys.U);
                value = false;
            }
            base.SetVisibleCore(value);
        }
        protected override void WndProc(ref Message m) {
            if (m.Msg == WM_HOTKEY && m.WParam.ToInt32() == MYKEYID) {
                this.Visible = true;
                if (this.WindowState == FormWindowState.Minimized)
                    this.WindowState = FormWindowState.Normal;
                SetForegroundWindow(this.Handle);
            }
            base.WndProc(ref m);
        }
        // P/Invoke declarations
        private const int WM_HOTKEY = 0x312;
        private const int MOD_ALT = 1;
        private const int MOD_CONTROL = 2;
        private const int MOD_SHIFT = 4;
        [DllImport("user32.dll")]
        private static extern int RegisterHotKey(IntPtr hWnd, int id, int modifier, Keys vk);
        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
        [DllImport("user32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);
    }
}

请注意,SetForegroundWindow() 函数是问题所在,也可能是您在问题中描述的问题的根源。当用户正在主动使用另一个窗口时,Windows 不允许应用程序将窗口推到用户面前。至少几秒钟的不活动状态才会让窗口窃取焦点。使用给定的代码,很容易看到,表单的任务栏按钮将会闪烁。避免将 ShowInTaskbar 属性设置为 false。对于此代码,没有必要这样做,在按下热键之前任务栏按钮不会显示。

Seeing KeyPressedEventArgs being used in your function looks really strange. Hot keys can be implemented by P/Invoking the RegisterHotKey() API function. It sends a message to your window when the hot key is pressed. Here's an example of a form that's invisible at start up, springs alive when you press the hot key. Ctrl+Alt+U in this case:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1 {
    public partial class Form1 : Form {
        private const int MYKEYID = 0;    // In case you want to register more than one...
        public Form1() {
            InitializeComponent();
            this.FormClosing += (s, args) => UnregisterHotKey(this.Handle, MYKEYID);
        }
        protected override void SetVisibleCore(bool value) {
            if (value && !this.IsHandleCreated) {
                this.CreateHandle();
                RegisterHotKey(this.Handle, MYKEYID, MOD_CONTROL + MOD_SHIFT, Keys.U);
                value = false;
            }
            base.SetVisibleCore(value);
        }
        protected override void WndProc(ref Message m) {
            if (m.Msg == WM_HOTKEY && m.WParam.ToInt32() == MYKEYID) {
                this.Visible = true;
                if (this.WindowState == FormWindowState.Minimized)
                    this.WindowState = FormWindowState.Normal;
                SetForegroundWindow(this.Handle);
            }
            base.WndProc(ref m);
        }
        // P/Invoke declarations
        private const int WM_HOTKEY = 0x312;
        private const int MOD_ALT = 1;
        private const int MOD_CONTROL = 2;
        private const int MOD_SHIFT = 4;
        [DllImport("user32.dll")]
        private static extern int RegisterHotKey(IntPtr hWnd, int id, int modifier, Keys vk);
        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
        [DllImport("user32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);
    }
}

Note that the SetForegroundWindow() function is the rub, possibly also the source of the problem you describe in your question. Windows doesn't permit an app to shove a window in the user's face when the user is actively using another window. At least several seconds of inactivity must expire before it will allow the window to steal the focus. With the given code, that is easy enough to see, the taskbar button of your form will be blinking. Avoid setting the ShowInTaskbar property to false. It isn't necessary to do so with this code, the taskbar button won't show up until the hot key is pressed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文