2016年1月29日金曜日

Emacsから無線LANを制御

 MacBook AirでEmacs1をつかっていて時々、いらっとすることがある。
 たとえば、無線LANをOFFにしたいとき、いちいちマウスでWi-Fiを「切」にしなければならない。EmacsからON/OFFできれば、いいのに——ざっとググってみたのだけれど、そういうものは見当たらなかった。しかし、MacOS自体は「networksetup」というコマンドをつかえば、ON/OFFできるらしい。
 ざっくりEmacsからつかえるようにした。
 ついでにモードラインにWi-Fiの状態を表示するようにも。2
 ポート名はハードコーディングだけど。

;; Wi-Fi接続時、モードライン表示
;; Wi-Fi Power (en0): On
(require 'cl)
(require 'deferred)

(defvar y-WiFi-mode-set nil)
(defvar y-WiFi-update-timer nil
  "Interval timer object.")

(unless y-WiFi-mode-set
  (setq-default mode-line-format
  (cons '(:eval (y-WiFi-mode-line))
        mode-line-format))
  (setq y-WiFi-mode-line t)
  (setq y-WiFi-update-timer (run-at-time nil 60
      'y-airport-listen)))

(lexical-let ((WiFi nil))
  (defun y-WiFi-mode-line ()
    (if WiFi
 (propertize "[On]" 'face '(:foreground "red"))
      (propertize "" 'face '(:foreground "blue"))))

  (defun y-airport-listen()
    "無線LANの状態問い合わせ"
    (interactive)
    (deferred:$
      (deferred:process 
 "networksetup" "-getairportpower" "en0")
      (deferred:nextc it
 (lambda (x)
   (if (string-match-p "On" x)
       (setq WiFi t)
     (setq WiFi nil))))))

  (defun y-airport-on()
    "無線LANをONにする"
    (interactive)
    (deferred:$
      (deferred:process 
 "networksetup" "-setairportpower" "en0" "on")
      (deferred:next
 (lambda()(setq WiFi t)))))

  (defun y-airport-off()
    "無線LANをOFFにする"
    (interactive)
    (deferred:$
      (deferred:process 
 "networksetup" "-setairportpower" "en0" "off")
      (deferred:next
 (lambda()(setq WiFi nil))))))

Footnotes:

1

GNU Emacs 24.5.1 (x86_64-apple-darwin14.3.0, NS apple-appkit-1347.57)

2

もしかしたらrequireが足りないかもしれない。