I want to simulate the pressing of Fn (Globe) + Control + arrow keys combo, but I’m encountering an issue where the Fn modifier seems to be ignored, and the system behaves as if only Control + arrow keys are pressed.
In macOS, the combination of Fn + Right Arrow (key code 124) is treated as End (key code 119), and even that didn’t have expected behavior. Instead of moving the window to the right edge of the screen on Sequoia, it switches to the next space, which is the default behavior for Control + Right Arrow.
Demo:
(I included Fn + Control + C to show that centering the window works for example.)
import SwiftUI
@main
struct LittleKeypressDemo: App {
var body: some Scene {
Window("Keypress Demo", id: "keypress-demo") {
ContentView()
}
.windowStyle(.hiddenTitleBar)
.windowResizability(.contentSize)
.windowBackgroundDragBehavior(.enabled)
}
}
struct ContentView: View {
var body: some View {
VStack(spacing: 20) {
KeyPressButton(icon: "arrowtriangle.right.fill", keyCode: 124)
KeyPressButton(icon: "arrow.down.to.line", keyCode: 119)
KeyPressButton(label: "C", keyCode: 8)
}
.padding()
}
}
struct KeyPressButton: View {
let icon: String?
let label: String?
let keyCode: CGKeyCode
init(icon: String? = nil, label: String? = nil, keyCode: CGKeyCode) {
self.icon = icon
self.label = label
self.keyCode = keyCode
}
var body: some View {
Button(action: { simulateKeyPress(keyCode) }) {
HStack {
Image(systemName: "globe")
Image(systemName: "control")
if let icon = icon {
Image(systemName: icon)
} else if let label = label {
Text(label)
}
}
}
.buttonStyle(.bordered)
.controlSize(.large)
}
}
func simulateKeyPress(_ keyCode: CGKeyCode) {
let fnKey = VirtualKey(keyCode: 63, flags: .maskSecondaryFn)
let controlKey = VirtualKey(keyCode: 59, flags: [.maskControl, .maskSecondaryFn])
let targetKey = VirtualKey(keyCode: keyCode, flags: [.maskControl, .maskSecondaryFn])
[fnKey, controlKey, targetKey].forEach { $0.pressAndRelease() }
}
struct VirtualKey {
let keyCode: CGKeyCode
let flags: CGEventFlags
func pressAndRelease() {
postKeyEvent(keyDown: true)
postKeyEvent(keyDown: false)
}
private func postKeyEvent(keyDown: Bool) {
guard let event = CGEvent(keyboardEventSource: nil, virtualKey: keyCode, keyDown: keyDown) else { return }
event.flags = flags
event.post(tap: .cghidEventTap)
}
}
Expected behavior:
Simulating the key combo Fn + Control + Right Arrow on macOS Sequoia should move the current window to the right half of the screen, instead of switching to the next desktop space.
Questions:
Is CGEventFlags.maskSecondaryFn enough to simulate the Fn key in combination with Control and the arrow keys? Are there alternative approaches or workarounds to correctly simulate this behavior? What’s the obvious thing I missing?
(Btw., window management is completely irrelevant here. I’m specifically asking about simulating these key presses.)
Any insights or suggestions would be greatly appreciated.
Thank you.
Post
Replies
Boosts
Views
Activity
Which method allows me to apply larger-than-default rounded corners to a macOS window while maintaining the system’s dynamic, contrasting border – similar to what’s seen in the Control Center popup? (Control Center has a corner radius of 16, the default system window is 10.)
While I know how to closely achieve this effect manually for my plain panel, I'd like to leverage the built-in method and get it for free from the OS.
I’ve spent way more time on this problem than I'm willing to admit, and searched extensively, but haven’t found any solution. I’d really appreciate any pointers.
Thank you.
Is there a SwiftUI idiomatic way to selectively remove the defualt (File, Edit, View, Window) menus from the menu bar in a macOS app, while keeping other menus like the AppName menu intact? The app I’m building is a simple utility app, and Edit and View menus are not relevant in this context. Any guidance would be appreciated.
It’s quite easy to detect if Mac has an illuminated keyboard with ioreg at the command line…
ioreg -c IOResources -d 3 | grep '"KeyboardBacklight" =' | sed 's/^.*= //g'
…But how can I programmatically get this IOKit boolean property using the latest Swift? I’m looking for some sample code.
We have a simple sandboxed app with important checkbox, and toggling it enables a system-wide setting. In order for this setting to be applied at login, we use a Service Management login item installed via SMLoginItemSetEnabled, located in in the main app bundle’s Contents/Library/LoginItems folder.
A couple of questions:
General — does the helper tool need to launch the main app, or can it apply the setting itself? All we have to do is apply a setting at login without showing UI, then terminate the app.
Technical — does the helper tool need to be a full application bundle, or can it be just a simple sandboxed command line tool, since it has no UI?
Any suggestions are welcome on how to elegantly solve this and still fly in Mac App Store.
Is there an API or a method for detecting which of the three main keyboard layouts – ANSI, ISO, or Japanese – a Mac notebook uses?
After fairly extensive research, I could not find any information about this.
After an extensive research, I haven’t found a canonical answer to what seems a fairly common task — placing a launch agent to the LaunchAgents folder.
I would like to copy a propriety list file to ~/Library/LaunchAgents/com.mycompany.MyAgent.plist from my sandboxed app.
Can this be achieved with app sandbox enabled?
Which entitlement should I use (if any)?
Will it pass the Mac App Store app review if I enable it?
Is there a best practice that I’m missing?
I know we’re not supposed to access a path outside of the app sandbox without the user’s consent, but I have a justified and legitimate case to copy a file with a particular com.mycompany.MyAgent.plist name to a very specific folder.
———
Note: I don’t need to manually start the launch agent. macOS will see my .plist file and load it automatically the next time it restarts. (Launch agents are regular user processes so none of this requires any special privileges.)
Of course, if I try to copy the .plist file, it’s placed in a folder relative to my app’s container rather than the user’s real home folder. If I disable the sandbox, I get the desired result.
Any help is greatly appreciated and good ideas are welcome. Thank you.