Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CLI support #371

Open
v-braun opened this issue Jun 9, 2020 · 21 comments
Open

Add CLI support #371

v-braun opened this issue Jun 9, 2020 · 21 comments
Labels
enhancement New feature or request niche Nice idea, but not enough demand for it

Comments

@v-braun
Copy link

v-braun commented Jun 9, 2020

First: thanks for this app!
I tried HyperSwitch for long time but it was so annoying that the order of windows (most recent window) is based on the active space, if you switch windows between spaces the order is messed up (maybe something that you can to the compare table on your website).

No my question:
I wanted to built a Alfred Workflow to list and search within windows, this app would be a good starting point to get all windows if it would have a CLI.

Is there something like this?

@lwouis
Copy link
Owner

lwouis commented Jun 10, 2020

Hi @v-braun! Thanks for sharing this feedback!

I'm not sure i get a clear picture of what that CLI would look like.

Could you please specify it more? Like example commands you would need to build your workflow, and what they output, in more details?

Currently there is none of that. The app is only usable through its GUI

@lwouis lwouis added the enhancement New feature or request label Jun 10, 2020
@v-braun
Copy link
Author

v-braun commented Jun 12, 2020

Hey, what I imagine is a CLI interface to query Windows, Apps and Spaces.
For my specific use case only windows are needed.

This interface would be cool:

# list all windows from all spaces
# options: 
# -o / --output (table or json): specify output format
# -s / --space: filter by space 
# -d / --display: filter by display
# -t : filter by title (regex??, fuzzysearch??)

#example: 
alt-tab window list -o json


# output:
[{
   "id": "unique window id",
   "appId": "process id of the app",
   "title": "window title",
   "size": {
      "height": 100,
      "width": 100
   }
}]


# activate a window
#example: 
alt-tab window activate <<window id>>

Other subcommands could be:

  • alt-tab window

    • subcommands
      • alt-tab window list
      • alt-tab window activate
      • alt-tab window resize
      • alt-tab window move
  • alt-tab space

    • subcommands
      • alt-tab space list
      • alt-tab space activate
  • alt-tab display

    • subcommands
      • alt-tab display list

@lwouis
Copy link
Owner

lwouis commented Jun 12, 2020

That's interesting! I have a few questions:

  • You said: "to query Windows, Apps and Spaces", but then there is nothing about Apps in the subcommands. Instead there is a subcommand for Displays. I guess you also said that you personally only have interest in Windows?

Regarding filtering, you wrote:

-s / --space: filter by space

-d / --display: filter by display

-t : filter by title (regex??, fuzzysearch??)

I wonder if filtering wouldn't be better done by the user. Like doing regex search in titles or fuzzysearch could be done by piping grep or fzf, or writting a program that feeds off the JSON output and sorts/filters it.

Do you care about the windows order? Should it be ordered by latest-used like in the graphical AltTab?

I'm wondering if this binary cli you want would be best as part of AltTab.app, or as a standalone binary. Some points to consider:

  • the cli doesn't need Screen Recording permissions as it doesn't output screenshots of the windows
  • the cli doesn't need the icons and other resources of the AltTab.app
  • the cli probably doesn't want the auto-update feature of AltTab.app
  • I think the target audience of each is quite distinct, thus bundling them together may be bloat to both sides (e.g. the previous points about icons, permissions, etc)

Another point is that AltTab builds an understanding of windows by listening to changes in apps, windows, user actions, permissions, etc. This means that cli you mention would only be a client, probably to an XPC server. Basically we would split the "system model" as an XPC server, and have a CLI frontend and the current GUI frontend query that backend.

Finally, I'm quite curious, could you describe the Alfred Workflow you are trying to build? I'm curious as to what you will do in Alfred that the current UI doesn't do for you, or couldn't be improved to do

@v-braun
Copy link
Author

v-braun commented Jun 12, 2020

a lot of questions, but looks like you like the idea wich is great 😀

The commands that I proposed are more general. For my specific workflow I need only a list of windows (id, title) and a subcommand to activate a window (focus).

The workflow that I want to build is:

  • search for window titles
  • select one in alfred
  • get it focused

There is a already such a workflow wich is very slow and ... there we come to the XPC server.
I already proposed there such kind of a solution (based on a unix socket or something like this):
mandrigin/AlfredSwitchWindows#31 (comment)

So let me try to recap your questions:

You said: "to query Windows, Apps and Spaces", but then there is nothing about Apps in the subcommands. Instead there is a subcommand for Displays. I guess you also said that you personally only have interest in Windows?

Youre right, forgot the app

I wonder if filtering wouldn't be better done by the user. Like doing regex search in titles or fuzzysearch could be done by piping grep or fzf, or writting a program that feeds off the JSON output and sorts/filters it.

Right again, I thought that could be optional and maybe could have a better performance if the cli is doing it already

Do you care about the windows order? Should it be ordered by latest-used like in the graphical AltTab?
In the workflow it would be good to have a default order, wich is the 'last active' order as in the app. A lot of window switcher cannot handle it well (order is only correct within a space, you did a great job hee). Maybe it is also possible to have a dedicated property on the window object that has the order, so that a consumer can use it

I'm wondering if this binary cli you want would be best as part of AltTab.app, or as a standalone binary. Some points to consider:

I think a server is a great idea, a cli client that can be used from other apps would be very cool to automate things (like automatically rearange windows for coding/design tasks, etc.)

Another point is that AltTab builds an understanding of windows by listening to changes in apps, windows, user actions, permissions, etc. This means that cli you mention would only be a client, probably to an XPC server. Basically we would split the "system model" as an XPC server, and have a CLI frontend and the current GUI frontend query that backend.

YEP! a XPC server and a client would be cool

Finally, I'm quite curious, could you describe the Alfred Workflow you are trying to build? I'm curious as to what you will do in Alfred that the current UI doesn't do for you, or couldn't be improved to do

type: win {query} will return a list of windows that match the query, user can select a window and it get focused.

@lwouis
Copy link
Owner

lwouis commented Jun 13, 2020

If your goal is to get a list of windows, and filter it based on criterias, I think you have rich existing solutions for that right now with Witch and Contexts. Have you tried those perhaps?

@v-braun
Copy link
Author

v-braun commented Jun 14, 2020

Yes, I tried Contexts for a while but wanted to have it integrated in alfred

@lwouis
Copy link
Owner

lwouis commented Sep 24, 2020

Interesting article about all the IPC solutions on macOS. A bit old but the author is also Alamofire's author and their skill shows in the writting.

@ayroblu
Copy link
Contributor

ayroblu commented Jan 3, 2021

I was curious if supporting the AppleScript commands would be sufficient here. I don't really understand how the objects and interfaces are defined, but maybe it's a minimal object export of some kind?
osascript has a js language interface too so theoretically easier to use for some people.
Obvious downside potentially of performance 🤷‍♂️️

@lwouis
Copy link
Owner

lwouis commented Jan 3, 2021

@ayroblu this sounds like equal or more work than a custom cli.

The reason this ticket represents a large amount of work is because it requires a new architecture.

Today, the app is a macOS app (i.e. a .app bundle). It runs a "background app", and presents an icon in then MenuBar. This app process is listening to global events such as key presses, mouse use, windows changes, app changes, preferences changes, etc.

For this ticket, we would need to isolate the core of the app which processes these events, and keeps track of windows and other things. Then we would run this as an XPC process, in the background. Then we would write a new "client" cli app, which you can call from the cli. That app would be very short lived, and would be invoked with something like at list windows. It would then send a request to the XPC process to get the list of windows, and after receiving it, would render it as text in stdout, and terminate.

Writing the new cli is probably easy and fun. Refactoring the current app to act as a background stateful server, is a lot of work. Also there are performance considerations to take into account with the new design. As well as maintenance considerations (i.e. another repo for the cli? How to deal with changes in one or the other repo? Backward compatibility? Forward compatibility? etc)

@ayroblu
Copy link
Contributor

ayroblu commented Jan 3, 2021

Okay, I'm not really sure how objects get exported for scripting by macOS, it did feel like less work than doing the rearchitecture, but I wouldn't know 🤷‍♂️

@lwouis
Copy link
Owner

lwouis commented Jan 3, 2021

how objects get exported for scripting by macOS

I don't know enough about this. I've never used it. If someone wants to explain and share a work plan, I'm interested.

@ayroblu
Copy link
Contributor

ayroblu commented Jan 3, 2021

Just as context, how Reminders works:

function run(args) {
  var Reminders = Application("Reminders");
  lists = Reminders.lists;
  for (var i = 0; i < lists.length; ++i) {
    console.log(lists[i].name());
  }
}

Then run osascript -l JavaScript <filename>.js (permissions etc)

Sadly this is extremely slow, like 4 seconds on my mac so I don't think this is a great solution

@ayroblu
Copy link
Contributor

ayroblu commented Jan 3, 2021

Oh sorry for the repeated messages, I was thinking, the easiest way might actually just to persist it on disk somewhere? Just export a structured json when the underlying data changes? It might be slightly expensive, but not a crazy amount so

@lwouis
Copy link
Owner

lwouis commented Jan 3, 2021

That's a very interesting idea. We would need to define what's stored in more details, but probably a v1 of that feature could export windows with their details like which Space it's on, which screen it's on, the order of recently-used-ness, etc.

A worry is the performance hit it could add. It would probably be an opt-in preference anyway, so that's probably fine. Another question is where that file would be stored. I think most places from Catalina onwards require a System permission to be granted first, which I can tell you from adding permission listening code before, is way harder to deal with than it should be.

I would love to give that a try in a local build, but I think other issues are more important, and I'm basically overwhelmed with the amount of issues at the moment. I even have some PRs open I need to deal with.

@ayroblu @v-braun are you interested in contributing perhaps? It's a nice scope for a first PR on the project

@ayroblu
Copy link
Contributor

ayroblu commented Jan 5, 2021

After having played with the code, it's actually pretty easy to (theoretically) expose a port to connect to with an API which allows you to do RPC calls. I actually don't think there's much refactoring as such to do, it's all global static variables anyways. My diff is good enough for the alfred use case, but I think for a proper solution, rpc / http would be pretty straightforward.
This would be similar to alfred's remote feature or I'm sure other remote systems apis

@lwouis
Copy link
Owner

lwouis commented Jan 6, 2021

Technical infra to communicate between processes is fine I'm sure. As I've said, the hard part is to re-architect the app from a all-in-one, performant monolithic process, into a client + a background server.

People who use the cli probably don't want the normal keyboard/mouse/trackpad event handling to happen. So we can't just add a cli client on top of the existing app. We have to have an architecture like this:

  • at cli client
  • AltTab.app desktop client

Both of them would communicate with a background server like at-server.

We would probably wrap both experiences in 2 packaging:

  • cli package: at cli client + at-server background server. We would add some kind of facility to monitor the server. Maybe add it to launchd, maybe even a UI like a menubar menu with "start/stop" AltTab server. Then the cli is a short-lived client that just sends a command and quits everytime
  • app package: AltTab.app which would contain at-server. It would boot the app bundle as it does today, except it would launch at-server in a headless mode, and communicate with it internally.

It's that separation that creating lots of work. It's a whole new approach with lots of added complexities. It would mean different repositories, releasing the cli package in addition to the .app of today. It would mean 2 distributions to maintain, update, develop. How would updating the cli look like? Another homebrew target maybe only?

Lots of questions, lots of work. It's a whole thing

@ayroblu
Copy link
Contributor

ayroblu commented Jan 6, 2021

Just to be clear, theoretically you could do that, but I think we'd get pretty far without bothering with most of that.

People who use the cli probably don't want the normal keyboard/mouse/trackpad event handling to happen

Personally I don't think this is a big deal, I think simply having the control to list windows and perform actions from shell while keeping all the existing functionality is perfectly fine

If you really want to create a cli client (I don't think it's necessary, just exposing an API is more than enough I think), monorepos are great, so it could just be another folder.

Personally the lowest effort way is to use some third party (atleast it looks pretty hardcore to roll your own) server, stick a few routes, listen on a port based on a preference, publish an API schema of some kind and be done with it

@lwouis
Copy link
Owner

lwouis commented Jan 6, 2021

I estimate that effort to be multiple months of work. I may be wrong though. PR welcome ;p

@Stvad
Copy link

Stvad commented Mar 28, 2021

I just had the same Idea that the original author here (wanted to use this as a foundation for an Alfred workflow).
Well I really want to accomplish #590, but I thought I can do that myself with the workflow if something like CLI existed 😅.

For other people coming here with the same idea - I've found https://github.com/mandrigin/AlfredSwitchWindows which is similar but has a bunch of issues and not currently supported 🙁.


It's unfortunate that it seems to require a lot of work.

As a hacky approach that might work here for the use-case of Alfred WF - would it be possible to, if a certain setting enabled, regularly (every second/a few seconds) dump the "state of the world" (all the windows in the LRU order) into a file?

The Alfred WF (and other integrating apps) can then read the file and use that info. @lwouis what do you think?
UPD: oh there is actually a PR for this 🙈 #761

@KhimairaCrypto
Copy link

Adding CLI support will unlock the possibility to use Aldred to switch windows :-). Please expose the same control over CLI.

@KhimairaCrypto
Copy link

I just had the same Idea that the original author here (wanted to use this as a foundation for an Alfred workflow).
Well I really want to accomplish #590, but I thought I can do that myself with the workflow if something like CLI existed 😅.

For other people coming here with the same idea - I've found https://github.com/mandrigin/AlfredSwitchWindows which is similar but has a bunch of issues and not currently supported 🙁.

It's unfortunate that it seems to require a lot of work.

As a hacky approach that might work here for the use-case of Alfred WF - would it be possible to, if a certain setting enabled, regularly (every second/a few seconds) dump the "state of the world" (all the windows in the LRU order) into a file?

The Alfred WF (and other integrating apps) can then read the file and use that info. @lwouis what do you think?
UPD: oh there is actually a PR for this 🙈 #761
I have not been able to find any workflow that provide full window support like alt-tab does!

@lwouis lwouis added the niche Nice idea, but not enough demand for it label Nov 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request niche Nice idea, but not enough demand for it
Projects
None yet
Development

No branches or pull requests

5 participants