How to Show a Window Without Stealing Focus on MACos

How to show a window without stealing focus on macOS?

I've been playing around with this a bit, and I seem to be able to produce this effect when the frontmost window is not from the same process as the frontmost application, which is what I suspect Spotlight is probably doing. I can achieve this like so:

  1. Set LSUIElement to YES in my app's Info.plist.

  2. In Interface Builder, set the window's class to NSPanel, check "Non Activating" in the Attributes Inspector, and set "isFloatingPanel" to YES in the User Defined Runtime Attributes under the Identity Inspector.

  3. During some time that some other application is in front (I just used a 5-second delay to give myself time to pop some other app to the front and select a text field), call makeKeyAndOrderFront() followed by orderFrontRegardless() on the window.

When I do this, I get the following (note the focus ring still drawn on Xcode's "Module" field):

Sample Image

Is it possible to move windows in background (without stealing focus)

Open 2 windows (or more) in Safari and try this. It will move the 2nd window 5 pixels to the right. This code should work for your application as well as System Events knows about the windows and can reposition them of other applications. Note that windows also have a size property you may want to use.

tell application "System Events"
tell process "Safari"
set theWindows to windows
if (count of theWindows) is greater than or equal to 2 then
set p to position of (item 2 of theWindows)
set position of window 2 to {(item 1 of p) + 5, item 2 of p}
end if
end tell
end tell

Show Window without activating (keep application below it active)

Either one of these should do the trick:

  • Use -[NSWindow orderFrontRegardless] to get a normal level window to the front without activating the corresponding app, or
  • Use -[NSWindow setLevel:] to increase the window level to something higher than NSNormalWindowLevel

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

Show window in Qt without stealing focus

It took me a while to find it but I found it: setAttribute(Qt::WA_ShowWithoutActivating);

This forces the window not to activate. Even with the Qt::WindowStaysOnTopHint flag

wxPython on Mac OS X: creating a wx.Frame without stealing focus

If you want to get native handle to window in Mac you can do

frame.MacGetTopLevelWindowRef()

and may be you can use pyobjc to interact with windows natively, but why don't you set focus on the window you want to after opening mini-frame?



Related Topics



Leave a reply



Submit