Keep Window on Top and Steal Focus in Winforms

Keep window on top and steal focus in WinForms

Visibility

Make the window a "Top-Most" window. This is the way the Task-Manager can remain on top of other windows. This is a property of a Form and you make the form top-most (floating above other windows) by setting the value to true.

You shouldn't need to override any of the "Active window" behaviour with the top-most setting.

Focus

I asked a similar question previously here on StackOverflow and the answer would solve your problem. You can make the application use a low-level input hook and get notification of the key-codes coming from the scanner. This way, your application always gets these keys even though the application does not have focus.

You may need to enhance the solution to squash the key-codes so that they are not transmitted to the "in-focus" application (e.g. notepad).

Since Windows 2000, there is no official mechanism for an application to grab focus without direct intervention of the user. Peeking at the input streams through the RawInputDevices hook is the only sensible way to go.

A number of articles may help (C# implementations)

  • RawInput article on CodeProject
  • MSDN documentation of RawInput

How to keep a Form always on top without stealing focus from the active Window?

  1. Make a standard Form, set its FormBorderStyle = none. Make it TopMost (this setting is another topic per se, I'm no going to discuss it here).
  2. Override CreateParams to set the WS_EX_NOACTIVATE and WS_EX_TOOLWINDOW extended styles. This prevents the Form from being activated when mouse events are generated inside its surface (see the docs about these styles).
  3. Add some non-selectable Button Controls to it (the ButtonNoSel Control shown below) and set their Tag property to the Unicode char corresponding to the Emoji image these buttons show.
  4. Add the same Click handler to all the Buttons.

These Buttons, when clicked, simply use SendKeys::Send() (a.k.a. SendInput()) to send the selected Unicode char to the foreground Window, casting to string the Tag property value.

This is how it works (setting the Emoji to a Web Page shown by FireFox):

Sample Image



using namespace System;
using namespace System::ComponentModel;
using namespace System::Windows::Forms;
using namespace System::Drawing;

public ref class frmKeyBoard : public System::Windows::Forms::Form
{
public:
frmKeyBoard(void) { InitializeComponent(); }

// [...] Initialization...

protected:
property System::Windows::Forms::CreateParams^ CreateParams {
virtual System::Windows::Forms::CreateParams^ get() override {
auto cp = Form::CreateParams;
cp->ExStyle |= (WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW);
return cp;
}
}

// Event handler for all the Buttons
private:
System::Void buttonNoSelAll_Click(System::Object^ sender, System::EventArgs^ e) {
Control^ ctl = safe_cast<Control^>(sender);
SendKeys::Send(ctl->Tag->ToString());
}
};

Add this simple Custom Control to the Project.

This Control simply uses Control.SetStyle, setting ControlStyles::Selectable = false to prevent the child Control to become the ActiveControl when interacted with, since it doesn't receive the focus.

using namespace System;
using namespace System::Windows::Forms;
using namespace System::ComponentModel;

namespace CustomControls {
[ToolboxItem(true)]
public ref class ButtonNoSel : public System::Windows::Forms::Button
{
public:
ButtonNoSel(void) {
this->InitializeComponent();
this->SetStyle(ControlStyles::Selectable, false);
}

private:
void InitializeComponent(void) {
this->UseVisualStyleBackColor = true;
}

protected:
~ButtonNoSel() { }
};
}

Note that this Form must run on its own thread.

If you need to show this Form from another one, use Task.Run() to show it as a Dialog Window, calling ShowDialog(). This will start the Message Loop.

For example, from a Button.Click handler of another Form (here, named MainForm).

private: 
void ShowKeyboard() {
frmKeyBoard^ fk = gcnew frmKeyBoard();
fk->ShowDialog();
delete fk;
}

private:
System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
Task::Run(gcnew Action(this, &MainForm::ShowKeyboard));
}

How to prevent control from stealing focus?

ugh. you've probably already thought of this but can you disable the control's window during the period (or a guesstimation) when it tries to take focus, without hurting the user experience?

How to make a window always stay on top in .Net?

Form.TopMost will work unless the other program is creating topmost windows.

There is no way to create a window that is not covered by new topmost windows of another process. Raymond Chen explained why.

Show a Form without stealing focus?

Hmmm, isn't simply overriding Form.ShowWithoutActivation enough?

protected override bool ShowWithoutActivation
{
get { return true; }
}

And if you don't want the user to click this notification window either, you can override CreateParams:

protected override CreateParams CreateParams
{
get
{
CreateParams baseParams = base.CreateParams;

const int WS_EX_NOACTIVATE = 0x08000000;
const int WS_EX_TOOLWINDOW = 0x00000080;
baseParams.ExStyle |= ( int )( WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW );

return baseParams;
}
}

Bring window to front w/out focus

This may help you:

[DllImport("user32.dll")]
public static extern bool SetWindowPos (IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
void Exmpl() {
IntPtr HWND_TOPMOST = new IntPtr(-1);
uint SWP_NOACTIVATE = 0x0010;
uint SWP_NOMOVE = 0x0002;
uint SWP_NOSIZE = 0x0001;
SetWindowPos(form.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}


Related Topics



Leave a reply



Submit