Jump to content

Allow users to detect when Alfred is in focus


vitor

Recommended Posts

While replying to another user’s question that required Alfred to be in focus, in the back of my mind I was already thinking it would be impossible since I already knew the usual AppleScript way to detect if Alfred is the frontmost app does not work (even in Compatibility Mode).

 

However, I recalled the Hotkey feature can be scoped to specific apps, and decided to give it a try. To my surprise, it works, so Alfred can detect if itself is the frontmost app. Why not allow users to do the same? Until now I thought this wouldn’t be possible in any way due to some design choice that made Alfred undetectable to be the frontmost app to any app. But if it can detect itself as the frontmost app, then there’s no reason that capability should be constrained to its own Hotkey feature.

 

This is a feature I always wanted, as it would allow a slew of more workflow interactions, making Alfred be able to act as a kind of status bar (examples of use cases include checking for CPU usage of running apps or checking the status of a file download). The solution we have so far is far from ideal.

Link to comment
Share on other sites

These are two essentially different scenarios even though they sound linked.

 

I think the underlying, and less cludgy request here is: Make it possible for script filters to re-run (possibly timed?) if Alfred is still visible and the script filter is still the current context.

Link to comment
Share on other sites

48 minutes ago, Andrew said:

I think the underlying, and less cludgy request here is: Make it possible for script filters to re-run (possibly timed?) if Alfred is still visible and the script filter is still the current context.

 

Yes, that would very much fit the use case, and would be cleaner. Something like “auto rerun Script Filter every X seconds”.

 

Being able to detect Alfred is in focus was my suggestion as I figured that might be simpler to accomplish on your end, even if it took a bit more work on mine.

Link to comment
Share on other sites

It would be quite a bit easier / cleaner to just give the option to rerun the script every x seconds, perhaps in the "Run Behaviour" options. I'll take a look at this before the next release and may add it if it's not too disruptive to the rest of the release :)

Link to comment
Share on other sites

11 hours ago, Andrew said:

It would be quite a bit easier / cleaner to just give the option to rerun the script every x seconds, perhaps in the "Run Behaviour" options. I'll take a look at this before the next release and may add it if it's not too disruptive to the rest of the release :)

 

On a somewhat related note, can you add the current workflow keyword to Alfred's environmental variables? That would be a huge help for workflows that want to call themselves.

 

I know you can call an External Trigger instead, but you know I really don't like that mode, and randomly (from a user's perspective) switching modes because a workflow's implementation requires it to call itself is bad UX.

Link to comment
Share on other sites

@deanishe the reason I favour external trigger over simple keyword callback is that the external trigger locks the input to that specific workflow. When simply calling the workflow keyword, this can be ambiguous if a user has multiple items with the same keywords (muddling the results, a worse UX). I'll have a think about other solutions based on what you are trying to achieve.

Link to comment
Share on other sites

15 minutes ago, Andrew said:

@deanishe the reason I favour external trigger over simple keyword callback is that the external trigger locks the input to that specific workflow. When simply calling the workflow keyword, this can be ambiguous if a user has multiple items with the same keywords (muddling the results, a worse UX). I'll have a think about other solutions based on what you are trying to achieve.

 

Then how about letting a workflow call itself via an External Script in "keyword mode", which behaves precisely as if the user had entered the keyword and chosen that workflow?

 

I'd like to be able to write a workflow that behaves like Alfred's navigation mode without the risk of everything breaking if the user changes the keyword.

Link to comment
Share on other sites

@deanishe filesystem navigation mode is in a separate context (i.e. without keyword). Is there any reason you can't achieve what you're trying to do with one script filter and a combination of (json) autocomplete / invalid arguments? I'm trying to understand the necessity to call back the workflow on itself in this case, then I'll be able to come up with a cleaner solution.

Link to comment
Share on other sites

3 hours ago, Andrew said:

@deanishe filesystem navigation mode is in a separate context

 

It's nothing to do with the context. I'd like to be able to drill down and navigate back up again in my workflows as easily as you can in navigation mode.

 

The only way to do this is using delimited queries (with e.g. " 〉␣". If the user deletes the trailing space (so the query now ends with the delimiter), the Script Filter detects this, drops the last segment of the query and calls itself again.

 

With my Smart Folders workflow, for example, the keyword is .sf, so you enter .sf and the Script Filter shows a list of your Saved Searches. If you TAB on one (say, "MKV Episodes"), the query expands to .sf MKV Episodes 〉␣ and the Script Filter shows the contents of that Saved Search. You can continue typing to filter the contents of the Saved Search. OTOH, if you press backspace and delete the trailing space (i.e. query is now .sf MKV Episodes 〉), the Script Filter jumps back to the previous "level", showing all your Saved Searches, i.e. query is now .sf

 

That is to say, it works like navigation mode. Deleting the delimiter (or the trailing space in this case) pops the entire last "level" off the query, instead of just deleting the last character.

 

The only way to do that (that I know of, at any rate) is to call Alfred again using the workflow's keyword. Because Alfred doesn't tell you what keyword was used, you have to hardcode it. So if the user has changed the keyword, the workflow is now broken.

 

There's no way to back up to the "workflow root" with External Triggers. You either need to add an extra "Go back" result that points to a corresponding External Trigger or "force" the user into External Trigger mode as soon as they start typing a query. With CMD+Backspace, you either stay in the External Trigger you're in or exit the workflow completely.

 

Link to comment
Share on other sites

On 14/10/2016 at 0:52 PM, Andrew said:

It would be quite a bit easier / cleaner to just give the option to rerun the script every x seconds, perhaps in the "Run Behaviour" options. I'll take a look at this before the next release and may add it if it's not too disruptive to the rest of the release :)

 

I'd love to see the ability for workflows to programatically re-run themselves as and when necessary (e.g. via tell application "Alfred 3" to rerun).

 

This is another reason that workflows call themselves via AppleScript (and what prompted me to ask for the keyword in envvars above, as they're related in my mind).

 

It's very common for Script Filters to show a locally-cached copy of the data from an application/webservice and update the cache in a separate process. It'd be great if that separate process could tell Alfred to re-run the Script Filter if the cached data have changed.

 

"Re-run every X seconds" would broadly suck for this, as few Script Filters that aren't written in compiled languages run fast enough for it not to be very obvious to (and annoying for) the user when they reload. Reloading once if and when there are fresh data is good. Reloading every few seconds just in case there are, not so much.

 

Link to comment
Share on other sites

@deanishe the first iteration of this will likely be defined in the JSON/XML returned from the script filter... i.e. "rerun script in x seconds if still focused". This would give a bit more dynamic control over duration / repeat for reload. It's also worth mentioning that Alfred will keep the current results visible while reloading the subsequent results, so you could theoretically do this (yet to be tried and tested)...

 

On first run of the script, show cached results and ask Alfred in the JSON to re-run the script pretty much immediately. Don't return updated results until you have them, and as soon as you do, return them and Alfred updates the results. This way, you get two runs, one with your cached, and one when you have a second set of results.

 

Cheers,

Andrew

Link to comment
Share on other sites

5 minutes ago, Andrew said:

@deanishe the first iteration of this will likely be defined in the JSON/XML returned from the script filter... i.e. "rerun script in x seconds if still focused". This would give a bit more dynamic control over duration / repeat for reload. It's also worth mentioning that Alfred will keep the current results visible while reloading the subsequent results, so you could theoretically do this (yet to be tried and tested)...

 

On first run of the script, show cached results and ask Alfred in the JSON to re-run the script pretty much immediately. Don't return updated results until you have them, and as soon as you do, return them and Alfred updates the results. This way, you get two runs, one with your cached, and one when you have a second set of results.

 

Cheers,

Andrew

 

That sounds better than a having the option in the Run Behaviour settings. The Script Filter at least knows if the cache is older than the refresh interval.

Link to comment
Share on other sites

20 hours ago, Andrew said:

@deanishe the first iteration of this will likely be defined in the JSON/XML returned from the script filter... i.e. "rerun script in x seconds if still focused". This would give a bit more dynamic control over duration / repeat for reload. It's also worth mentioning that Alfred will keep the current results visible while reloading the subsequent results, so you could theoretically do this (yet to be tried and tested)...

 

On first run of the script, show cached results and ask Alfred in the JSON to re-run the script pretty much immediately. Don't return updated results until you have them, and as soon as you do, return them and Alfred updates the results. This way, you get two runs, one with your cached, and one when you have a second set of results.

 

Cheers,

Andrew

 

@andrew This would be great.  In my use case for my Today workflow, the ScriptFilter first shows cached data.  In the background it spawns an update query.  If the update detects changed data against what was already saved I hide Alfred and re-open it to refresh the data.  This looks kind "dumb" to the users - but it works.  It would be much nicer if there was a better way to do this.

 

 

 

 

 

Link to comment
Share on other sites

  • 2 weeks later...

If you update to the Alfred 3.2 pre-release, you can now do two pretty powerful things with script filters... session variables and rerunning filters.

 

The documentation is yet to be updated, but I've added a new built in getting started workflow called "Advanced Script Filters" with a populated read-me. This workflow has both the JSON and XML versions of Script Filters both using variables and rerunning filters with timers.

 

Let me know how you get on! :)

Link to comment
Share on other sites

Really excited about the feature! Thank you!


Already implemented it in DownVid, did a quick run, and it seems to work great. Will test more features throughout the day.

 

There are a few typos in the Advanced Script Filters workflow. On the top left node:

uGCuqdP.png

 

“uses sets” sounds weird.

 

On the nodes on the right side.

dlXZcpd.png

 

The bottom one says “JSON Version” (instead of “XML”) and they both say “This Acript Filter”.

Edited by vitor
Link to comment
Share on other sites

So far, so awesome. I’ve added both features to DownVid and UploadFile, and they’re a pleasure to use and seem to be working splendidly.


I do, however, have a tiny note regarding Advanced Script Filters. Going by jvar and xvar, understanding how the variable is actually read and set was a bit of a pain (a lot of “why isn’t it working like this?”). Problem was those example have two different variables that are handled differently but named (closed to) the same. Only by fiddling with the example itself did it click: COUNTER and counter.

 

It was partly my fault for not paying enough attention when analysing the example, but I think those would be better being renamed to something that makes it clearer they’re two different variables. Something like COUNTER_TEMPORARY and counter or something. Doesn’t really matter, as long as capitalisation isn’t the only way to differentiate them.

Edited by vitor
Link to comment
Share on other sites

Dean is correct - 'counter' is just the passed in environment variable you are reading.

 

In your returned XML or JSON, you are setting variables which will be passed out of that workflow object down the stream, or passed back in as variables if the script is run again within the same context... so useful for two things, but really quite useful for setting state between same runs.

 

This workflow example was just thrown together, but you are right, it would probably have better clarity if 'counter' wasn't a global namespace variable.

Link to comment
Share on other sites

To be clear, I do fully understand the difference between the two variables. However, bash does not care about capitalisation in variable names (in ruby, for example, an all-uppercase variable is a constant — somewhat, as you can still change it but you’ll get a warning), so I always make my (bash) variables lowercase, which is probably why my brain didn’t even process them as different, at first. I simply read counter and didn’t even realise they were different capitalisations until I fiddled with them.

Link to comment
Share on other sites

16 minutes ago, deanishe said:

bash variables are case-sensitive, though. COUNTER and counter are two different variables.

 

Yes, I meant it doesn’t care in terms of meaning (unlike ruby, which does care and makes it either a variable or a constant depending on capitalisation). In bash you need extra words (readonly, local) for such distinctions.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...