How to determine if an app is at the side of the stage manager in macOS Ventura - applescript

I have a JavaScript for Automation (JXA) function to determine which state a macOS app is currently in:
function getAppState(appName) {
if (!Application(appName).running()) {
return "APP_NOT_RUNNING";
}
const proc = Application("System Events").processes.byName(appName);
if (proc.windows.length === 0) {
return "APP_RUNNING_NO_WINDOWS";
}
if (proc.frontmost()) {
return "APP_RUNNING_FRONTMOST";
}
// with Ventura stage manager, it seems this is all we can find out;
// proc.miniaturized/visible/zoomed won't tell us if the app has an open window on the
// screen or not
return "APP_RUNNING";
}
It tells me if an app is currently running, and if it is, if it has any application windows and if it is currently at the front.
I would like this script to return another value, let's call it APP_RUNNING_AT_THE_SIDE when the app is shown at the side in Stage Manager mode in macOS Ventura. I mean apps in a state like those in this screenshot:
I've tried to check the properties miniaturized, visible, zoomed of both Process and Application.Window with no luck – they always return the same values, no matter if an app is shown fully on the screen or small at the side.
Is there a way to determine if an app is at the Stage Manager side with JXA? Or perhaps someone knows an AppleScript solution that I can port to JXA?

Related

How do I support Call Mute (Universal Mute) in my app for Windows 11 22H2?

Windows 22H2 introduces a new hotkey (Win+Alt+K [See Keyboard shortcuts in Windows under "Windows Logo Key shortucts"]) to mute calls. It corresponds to this UI in taskbar:
It works when I use Teams, but not when I use Mumble:
The shortcuts guide indicates that it's available in Windows 11 22H2 for apps that support "Call Mute":
Toggle microphone mute in apps that support Call Mute. Available starting in Windows 11, version 22H2.
What APIs do I need to consume in order to support this new hotkey?
Disclaimer: I work for Microsoft.
There are 2 steps needed to support the Universal Mute button in your own apps:
Create a new VoipPhoneCall with the VoipCallCoordinator.
Handle the VoipCallCoordinator.MuteStateChanged event and fire the appropriate NotifyMuted or NotifyUnmuted function when your app has muted/unmuted in response.
For example:
using Windows.ApplicationModel.Calls;
var coordinator = VoipCallCoordinator.GetDefault();
coordinator.MuteStateChanged += (e, args) => {
Console.WriteLine($"Mute changed! - {args.Muted}");
// Respond that the app has muted/unmuted.
if (args.Muted) {
coordinator.NotifyMuted();
} else {
coordinator.NotifyUnmuted();
}
};
// No change until you press enter here:
Console.WriteLine("Press Enter to 'start' a call. Ctrl-C to exit.");
Console.ReadLine();
var call = coordinator.RequestNewOutgoingCall("context_link_todo", "Satya Nadella", "DummyPhone", VoipPhoneCallMedia.Audio);
call.NotifyCallActive();
// Win-Alt-K will display your app muted/unmuted until you press enter:
Console.WriteLine("Press Enter to 'end' the call.");
Console.ReadLine();
call.NotifyCallEnded();
See https://github.com/citelao/Universal-Mute for a full C# demo.

Xamarin Tap Simulation (ADB)

I have been using ADB to simulate touch commmands in my application, the plan is to develop a sort of keymapper application that simulates touches in external applications(I don't feel comfortable sharing the app idea in public, despite there already being some similar applications on the play store).
Essentially I use am using adb to input tap commands from my C# code like so:
Runtime r = Runtime.GetRuntime();
Java.Lang.Process p = null;
try
{
p = r.Exec("input tap 900 1900");
}
catch (System.Exception e)
{
Console.WriteLine(e.Message);
}
However, it only seems to work in my application (eg: views in my application or the screen area of my app).
It does not work on other apps or even on the three buttons on the bottom bar.
If I use the terminal provided by visual studio (Open Android Adb Command Prompt), then I am to fire tap commands (adb shell input tap x y) and they work everywhere, including on other apps.
However from my application's code when I fire these tap commands, they do not work.
Could you guys tell me of a way to do this?
P.S. I am using a xamarin.android foreground service to execute these taps on external apps.

Can a Windows 10 UWP (Desktop Bridge) app re-launch its own executable?

I have created a UWP app for Windows 10 using the Desktop Bridge. Mostly it works just fine, however my app needs to re-launch its own executable (with different command-line arguments). The two processes work together.
This works just fine for the non-UWP app, but when run as a UWP, I can't seem to re-launch my own executable (as derived from the process command-line). Should this be possible? Is there a particular way that I need to do it an UWP app?
Currently I get the error: Access is denied.
To launch your app the same way it would be launched when the user taps the app list entry, you can do this:
private async void StartMyApp()
{
var appListEntries = await Windows.ApplicationModel.Package.Current.GetAppListEntriesAsync();
await appListEntries.First().LaunchAsync();
}
This code assumes your package manifest contains only one application node. In case you have multiple, you need to pick the right one to call LaunchAsync on.

OS X: Launching app from dock is a no-op if app is already running headless (via NSApplicationActivationPolicyProhibited)

My app can run with a UI and run headless, chosen via a command-line argument. (I don't want to build two separate apps.) When running headless, I'm calling:
[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
during app initialization, and don't show any windows.
This all works fine, and I can run the app headed (via the dock) and headless (via another app passing the command-line argument) at the same time. The little dot shows up next to the dock icon only for the headed app. Good. The problem happens if the headless app is launched first. In that state (no dot in the dock), any clicking on the app icon (or launching via Spotlight or the Finder) does nothing, or sometimes brings up "You can’t open the application “Foo” because it is not responding." Presumably the OS thinks the app is already running headed, and is trying to activate it. Is there a way to convince it to ignore that background app and launch a new instance?
Quitting the background app allows the app to launch normally again from the dock.
I don't want to set LSBackgroundOnly in the plist, because that would require two separate apps unless I changed the setActivationPolicy to NSApplicationActivationPolicyRegular in the case of the headed app. But I've read that doing that causes various other bugs, like the menu bar not always showing up.
Any ideas?
I'm on OS 10.10.5 (the oldest OS I need to support). Thanks for any help!
Update: I just noticed that when clicking on the dock and it appears to do nothing, if there are no app windows open I can see that it actually unhides my app's main window (which was created hidden) but doesn't bring it to the front (presumably it notices that NSApplicationActivationPolicyProhibited is set, though that wasn't enough to prevent it from showing the window!).
Update 2: At this point, I'd settle for a way to notify the user that the reason the app isn't launching is that they need to quit the other app that has sublaunched the headless process. Of course this code would need to be in the headless app, since the headed doesn't even launch.
It looks like you can call setActivationPolicy from applicationShouldHandleReopen and set the policy back to NSApplicationActivationPolicyRegular at that time. I made a test app with the following code and it seems to behave as you describe you would like it to above (although I've only run it on 10.11.5):
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(aNotification: NSNotification) {
if NSUserDefaults.standardUserDefaults().stringForKey("background") == "true" {
NSApp.setActivationPolicy(.Prohibited)
print("launched in background")
}
}
func applicationShouldHandleReopen(sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
NSApp.setActivationPolicy(.Regular)
return true
}
}

Close other applications using swift

Is there a way to close running applications in swift? For instance, if the application I create needs to close safari.
Here's a Swift 5 version for closing running applications without using AppleScript (AppleScript is a perfect way but it isn't the only way), Safari is used as the example in this case:
let runningApplications = NSWorkspace.shared.runningApplications
if let safari = runningApplications.first(where: { (application) in
return application.bundleIdentifier == "com.apple.Safari" && application.bundleURL == URL(fileURLWithPath: NSWorkspace.shared.fullPath(forApplication: "Safari")!)
}) {
// option 1
safari.terminate()
// option 2
kill(safari.processIdentifier, SIGTERM)
}
SIGTERM instead of SIGKILL, referencing from here
Of course, make sure you notify the user of this activity since this may cause negative impact on the user-experience (for example, user-generated contents in the targeted application are not saved before terminating)
It is certainly possible via an applescript directly IF:
your app is not running sandboxed (note that if you plan to distribute it via the App Store, your app will be sandboxed)
OR
your app has the necessary entitlements to use applescript: com.apple.security.scripting-targets (apple needs to approve that AND you need to know which apps to target. this isn't a blanket permission)
then
https://apple.stackexchange.com/questions/60401/how-do-i-create-an-applescript-that-will-quit-an-application-at-a-specific-time
Can you execute an Applescript script from a Swift Application
if you aren't going for App Store complicity anyways, you might also use NSTask directly
scripts / code snippets:
How to force kill another application in cocoa Mac OS X 10.5
Can you execute an Applescript script from a Swift Application
short & sweet: technically yes, 'politically' maybe :D

Resources