notes from /dev/null

by Charles Choi 최민수


Using Emacs to make phone calls and lookup map places on macOS

20 Jun 2023  Charles Choi

I admit, I do take a perverse delight in making phone calls from my computer. On macOS, this can be achieved via the iPhone Cellular Calls feature, which proxies your computer to your iPhone’s calling capability. Tied to this feature is the ability to select a phone number in a native macOS app text field and use it to dial that number direct. An example is shown below from the Safari app.

screenshot of selected phone number in Safari with phone call context menu

To dial a number, the app translates the human-formatted phone number into a tel: URL scheme that is then used to open the FaceTime app to make the call.

We can emulate this behavior in Emacs. This post will show you how.

Making a Phone Call

First off is parsing the human-formatted phone number. We can do this by writing some regexps. Since I live in North America, I’ve chosen to use regexps that conform to the North American Numbering Plan (NANP). NANP formats phone numbers into the form +1 (xxx) xxx-xxxx. I've also chosen to make regexps that also accepts spaces and “.” as separators.

1
2
3
4
5
6
7
8
(defvar cc/pat-nanp-international "^+1 \
[(]*\\([0-9]\\{3\\}\\)[)]*\
[\\. -]\\([0-9]\\{3\\}\\)[\\. -]\\([0-9]\\{4\\}\\)$"
  "Regexp for North American Numbering Plan phone number including +1.")

(defvar cc/pat-nanp "^[(]*\\([0-9]\\{3\\}\\)[)]*[\\. -]\
\\([0-9]\\{3\\}\\)[\\. -]\\([0-9]\\{4\\}\\)$"
  "Regexp for North American Numbering Plan phone number without +1.")

In the above I’ve defined two separate regexps with capture groups, one to handle numbers starting with +1 and the other for those without it.

From these regexps we can write the following function to convert a phone number to a tel: URL.

1
2
3
4
5
6
7
8
(defun cc/nanp-phone-number-to-url (phone)
  "Convert PHONE number string to url \"tel:\"."
  (cond
   ((string-match cc/pat-nanp-international phone)
    (replace-regexp-in-string cc/pat-nanp-international
                              "tel:+1-\\1-\\2-\\3" phone))
   ((string-match cc/pat-nanp phone)
    (replace-regexp-in-string cc/pat-nanp "tel:+1-\\1-\\2-\\3" phone))))

It is then straightforward to write an interactive function that takes a phone number as a selected region, converts it to a tel: URL, and opens it.

1
2
3
4
5
(defun cc/call-nanp-phone-number (&optional start end)
  "Phone call the selected number (region) bounded between START and END"
  (interactive "r")
  (let ((phone-buf (buffer-substring start end)))
    (browse-url (cc/nanp-phone-number-to-url phone-buf))))

Putting the above code to work, we can show the following example of selecting the phone number +1 (415) 867-5309 and dialing it from Emacs.

gif movie of making a phone call from Emacs

Looking a place up in Apple Maps

A similar exercise can be done with searching for a place in the Maps app, which is accessible via the maps: URL scheme. Unlike a phone number, we will forego trying to interpret the selected region beforehand and just pass the region as the query to the maps: URL.

1
2
3
4
5
6
7
(defun cc/open-region-in-apple-maps (&optional start end)
  "Open region from START to END in Apple Maps"
  (interactive "r")
  (let* ((query-buf (buffer-substring start end))
         (mapURL (concat "maps://?q=" (url-encode-url query-buf))))
    (message "Searching for %s" query-buf)
    (browse-url mapURL)))

The following function lets you interactively enter an arbitrary place to search in Apple Maps.

1
2
3
4
5
6
(defun cc/search-apple-maps (search)
  "Open SEARCH query in Apple Maps"
  (interactive "MMap Search: ")
  (let ((mapURL (concat "maps://?q=" (url-encode-url search))))
    (message "Searching for %s" search)
    (browse-url mapURL)))

Putting the above code to work, we can show the following example of finding "Harlan Records, SF" in the Maps app from Emacs.

gif movie of finding a place in Apple Maps from Emacs

Modifying the above to work with Google Maps is left as an exercise to reader.

Context Menus

Note that all of the above examples are keyboard driven. They are not necessarily so. In fact, driving much of the above work was the desire to be able to perform these actions via a context menu. And it is very much doable, however I'll elaborate on how I've done this in a forthcoming post. For now, here's some demo screenshots of my context menu implementation that supports making a phone call or searching a location.

Emacs context menu - search maps example

Emacs context menu - search maps example

References

emacs   elisp   macos

 

AboutMastodonInstagramGitHub

Feeds & TagsGet Captee for macOS

Powered by Pelican