Any AppleScript way to set a calendar entry location and have it work properly?

Is there any way with AppleScript to set a calendar entry location and have it actually work properly?

I can set the text (and that is what Keyboard Maestro does in the Create Calendar Event action), but that is just text, it does not actually work as a geographical location. So you can’t navigate there for example.

It seems Calendar does some “magic” when you set the location and select from the dropdown menu to actually set a real location.

Copying from one entry to another does not appear to work. I found this discussion which indicates Shortcuts might be able to do it, but my tests trying that did not work any better, just the text was set.

Any ideas?

1 Like

I've seen the same problem with Shortcuts, it just sets it as text.

I have received a calendar invite from somewhere as an .ics file, and that did work, but when I tried to test it myself I couldn't get to work. I'll see if I can find one that works, and if it contains sensitive information I'll send it to you privately to see if you can figure out what it's doing.

2 Likes

That Apple Discussions page was the most informative source that I was able to find (and that’s never good news :wink:).

If a more elegant solution is not available, you could at least automate a click on the location field and paste in the location.

The following suggestions are not good! Maybe they will help encourage alternative ideas though. Maybe…

1) Click with co-ordinates

To use a click relative to the top-right corner of the window, you would need to calculate the length of the associated Event Title, because whenever the title wraps to a new line, the following fields (including Location) are shifted down. That would still be unreliable for a typeface that isn’t monospace.

2) Click on found image

So instead, you could click at the found image. What image? Well you could always include something like a pin emoji at the start of your location value in the Applescript, e.g. (for Stairways Software!) “:round_pushpin: Willetton WA, Australia”.

Then your macro should click on that emoji and delete it, and follow that with simulated keypresses of and Return to handle the pop-up menu of suggested locations (which adds the “magic”).

Of course, unless your Location address is precise, you would not be able to rely upon one press of being enough.

Instead…

Is there a way of navigating to the Location field using keystrokes?

I will not help with AppleScript but in case of Shortcuts Sindre Sorhus has in their package Actions (Actions — Sindre Sorhus) has f.ex. Get location at coordinates, which converts text values to real location. Maybe it helps someone.

I've done a little more testing of this today and this is a summary of things:

  1. Using KM's Create Calendar Event creates the event but the location is just text, not a geographical location that can be navigated to.

  2. Using an .ICS file containing a calendar event which has a location also creates the location as just text, not a geographical location that can be navigated to.

  3. Using the "New Event" calendar action in macOS Shortcuts also creates the location as just text, not a geographical location that can be navigated to.

However, if you use the same .ICS file or Shortcut in iOS or iPadOS the calendar event is created with a geographical location - a small map showing the location is visible in the event. If that event is synchronised to macOS via iCloud the resulting event in the macOS calendar also contains the geographical location and the small map.

This is frustrating; the fact that the same ICS file will work in iOS but not macOS may be a bug in macOS, or there may be an underlying difference in the calendar apps on both that mean it can't be done in macOS. The fact that Apple's own Shortcuts have the same problem as KM is encountering suggests to me that the problem is in the Calendar App.

So unless @peternlewis can find a clever workaround (which I hope he is able to do!), I don't think KM can create an event with a "working" geographical location.

3 Likes

I'm unfamiliar with Calendar, but after taking a look at Shane Stanley's CalendarLib EC and some trial and error came up with this on my Mojave setup.

use AppleScript version "2.5"
use framework "Foundation"
use framework "EventKit"
use framework "CoreLocation"
use scripting additions
property author : "@CRLF"

--Much of this script comes from Shane Stanley's CalendarLib EC v1.1.5
--Freeware | Late Night Software
--                 https://latenightsw.com/freeware/

-- Usage: tonight 7–8 PM at Mott St & Canal St, NYC
set theEventID to my makeCalendarEventWithTitle:"Mott Street dinner" startHour:19 endHour:20 address:"Mott St & Canal St New York NY" latitude:40.71797 longitude:-73.99991 notes:"Arrive early"
return "Created Mott Street event with ID: " & theEventID

on makeCalendarEventWithTitle:theTitle startHour:startH endHour:endH address:theAddress latitude:lat longitude:lon notes:theNotes
	-- 1. Event store + auth
	set theEventStore to current application's EKEventStore's alloc()'s init()
	(theEventStore's requestAccessToEntityType:0 completion:(missing value))
	
	-- 2. Wait up 30 s for authorization
	set deadline to (current application's NSDate's dateWithTimeIntervalSinceNow:30)
	repeat
		set authStatus to current application's EKEventStore's authorizationStatusForEntityType:0
		if (authStatus as integer) = 3 then exit repeat
		if ((current application's NSDate's |date|())'s timeIntervalSinceDate:deadline) > 0 then exit repeat
		delay 0.25
	end repeat
	
	if (current application's EKEventStore's authorizationStatusForEntityType:(0 as integer)) is not 3 then error "Calendar access not granted."
	
	-- 3. Get a writable calendar
	set theCalendar to theEventStore's defaultCalendarForNewEvents()
	if theCalendar = missing value then
		set allCals to theEventStore's calendarsForEntityType:0
		if (allCals's |count|()) = 0 then error "No writable calendars available."
		set theCalendar to allCals's firstObject()
	end if
	
	-- 4. Today’s start/end times
	set nowDate to current application's NSDate's |date|()
	set sysCal to current application's NSCalendar's currentCalendar()
	set comps to (sysCal's components:((current application's NSCalendarUnitYear) + (current application's NSCalendarUnitMonth as integer) + (current application's NSCalendarUnitDay as integer)) fromDate:nowDate)
	(comps's setHour:startH)
	(comps's setMinute:0)
	set startDate to sysCal's dateFromComponents:comps
	(comps's setHour:endH)
	set endDate to sysCal's dateFromComponents:comps
	
	-- 5. Build the event
	set theEvt to current application's EKEvent's eventWithEventStore:theEventStore
	(theEvt's setCalendar:theCalendar)
	(theEvt's setTitle:theTitle)
	(theEvt's setStartDate:startDate)
	(theEvt's setEndDate:endDate)
	if theNotes is not missing value then (theEvt's setNotes:theNotes)
	
	-- 6. Structured location (Mott St & Canal St, NYC)
	set theLoc to (current application's CLLocation's alloc()'s initWithLatitude:lat longitude:lon)
	set theStruct to current application's EKStructuredLocation's alloc()'s init()
	(theStruct's setTitle:theAddress)
	(theStruct's setGeoLocation:theLoc)
	(theStruct's setRadius:60.0)
	(theEvt's setStructuredLocation:theStruct)
	(theEvt's setLocation:theAddress)
	
	-- 7. Save 
	set {ok, err} to (theEventStore's saveEvent:theEvt span:(current application's EKSpanThisEvent) commit:true |error|:(reference))
	if (ok as boolean) is false then error (err's |localizedDescription|() as text)
	
	return (theEvt's |calendarItemExternalIdentifier|()) as text
end makeCalendarEventWithTitle:startHour:endHour:address:latitude:longitude:notes:


3 Likes

So it looks like the event has a structured location, which is not apparently available via AppleScript. A structured location is just text and a longitude&latitude.

So it does not look like it can be done via AppleScript, except as shown by @CRLF via using (JXA) Foundation, etc. And even then, it can only be done if you can know the longitude&latitude, which Keyboard Maestro could not know in general.

It’s likely that AppleScript copying an event will keep the structured location, so that would likely work as a possible solution for my case, but not for a general solution or a solution in Keyboard Maestro.

2 Likes

Just to help you towards a solution - this is what I do:

Assuming your AppleScript has created a new event by something like this:

set newEvent to make new event in calendar varCal at end with properties {description:varDesc, summary:varName, location:varLocation, start date:varStart, end date:varEnd, allday event:varAllday}

You can then go to that new event in Calendar with the AppleScript command:

show newEvent

Once the event is open in Calendar I use Keyboard Maestro interface Actions to select the location text in the event (at this point it is there but just text), cut it to the clipboard and paste it in again. This forces Calendar to do its "magic" and make a real location shown on a map.

I know this is not the solution you are after but it does work. The key is to open the event after creating it. And this is the one reason I do not use the built in Keyboard Maestro "Create Calendar Event" Action as that does not open the new event it has created. Using just AppleScript to create the event, it can be opened. So, this is also a round about way of asking if Keyboard Maestro's Create Calendar Event Action could open the new event it has created :slightly_smiling_face:

4 Likes

Hello Peter (@peternlewis):waving_hand:

Hope you’re doing well…

Just stumbled across this thread….

He‘s done a superb job with his ASObjC Code by using nearly the same structure that Shane‘s Library uses (if I remember correctly).

Doesn‘t have KM an Action that gets the users Location? If yes, does it have a Set to Variable Option? - If that’s the case why not using his Code and create The Action with it ?

If a KM user would use the Get Location Action (if it exists) beforehand to get the Longitude and Latitude into an Variable then the user could use these values in the Action or leave them empty when there’s no need of a Location at all.

Otherwise - another idea would be to maybe use the CoreLocation Framework to get these Values inside the Action (inside the ASObjC code) and put a Checkbook in so that the KM user could enable it to write his Location out to the calendar.

But since CoreLocation alone does not give other Values except the users current location without having MapKit envolved (maybe!) there would be some more code to write.

Maybe you could get Shane’s help on the MacScripter or LNS Forums to get a working solution.

I’ve inspected a lot ASObjC code to get quite a good understanding and probably have an idea on how the code works but I can not write code like that myself just jet.

Begin Off Topic: I wasn’t able to get the other thing ready for you but hopefully soon! I’m getting healthier. (End Off Topic)

Greetings from Germany :germany: to Australia :australia:

Tobias

An alternative would be to set the url property of the event to one of Maps URL Schemes, such as maps://?address=[address]

Clicking the link in Calendar opens the Maps app to the address.

Not as visually pleasing as an inset map, the clickable url works roughly the same.

The url field, of course, is not limited to the Maps URL Schemes and will take other urls, such as Google Map urls, just as readily.

Here's a macro that percent encodes an address, appends it to maps://?address= and sets an event and its url property to the url.

Image

AppleScript
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

set kminstance to system attribute "KMINSTANCE"
tell application id "com.stairways.keyboardmaestro.engine"
	set theURL to getvariable "localURLScheme" instance kminstance
	set theSummary to getvariable "localEventSummary" instance kminstance
end tell

tell application id "com.apple.iCal"
	tell calendar "Home"
		set theID to uid of (make new event with properties {summary:theSummary, url:theURL})
	end tell
end tell

Set Event URL to maps url scheme.kmmacros (4.9 KB)

Gah! :man_facepalming:t2:

KM has this base covered as well--of course!

Just use the URL: field in the Create Calendar Event Action.

1 Like

This wouldn’t make the leave to arrive by time thing work though.

2 Likes

Sure, but the event is for a different location, not the Mac’s location.

To create the structured location, you need the long/lat of the target location.

I like this. It means as well as having an Apple Maps location at the head of the event, there can also be a link to Google Maps in the URL field.

1 Like