Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
15
Help us understand the problem. What is going on with this article?
@tasuwo

Macbook の内臓キーボードの無効/有効を自動で切り替える (macOS Sierra)

More than 3 years have passed since last update.

2017/07/02 追記

kextunload してもキーボードが無効化されなくなってしまっていました。
原因はわかりませんが、代替手段としては tekezo/Karabiner-Elements: The next generation Karabiner for macOS Sierra を使用するのが良いようです。

追記終了

macOS Sierra にしたら,Karabiner が使用できなくなりました.それに伴い,外部キーボードを接続しても内臓キーボードが無効化されなくなりました.これを解決するため,内臓キーボードの有効化/無効化の方法を調べ,その自動化を試みた,という話です.

結論から言うと,自動化してみたはいいものの,キーボードの接続/取り外しから有効/無効の切り替えまでに最悪5秒程かかってしまい,あまり実用的ではありません.しかし,

  • 外部キーボードの付け外しはそこまで頻繁に行わない
  • 内臓キーボードの有効化をし忘れを防げる
    • 無効化したままスリープし,次回 wake 時に内臓キーボードが効かずに焦ることがなくなる

という点で考えれば使えるかも?自分はしばらく使ってみます.

2016/10/29 追記
他のMacbookでも利用したかったので Github にリポジトリを公開しました.
tasuwo/toggleMacbookInternalKeyboard: This scripts detect an external keyboard connection and disable internal keyboard of macbook instead of karabiner

内臓キーボードの無効化

内臓キーボードは,対応する kext をアンロードすることで無効にできるようです.

  • KEXT (Kernel EXTension)
    • その他の通り,カーネルを拡張するためのモジュール
    • その多くはデバイスドライバ
    • その大体が /System/Library/Extensions にある
コマンド 効果
kextload kextのロード
kextunload kextのアンロード
kextstat ロードされているkextの確認

以下のコマンドでロード/アンロード(有効化/無効化)が行えます.

# 内臓キーボードの無効化
$ sudo kextunload /System/Library/Extensions/AppleUSBTopCase.kext/Contents/PlugIns/AppleUSBTCKeyboard.kext/
# 内臓キーボードの有効化
$ sudo kextload /System/Library/Extensions/AppleUSBTopCase.kext/Contents/PlugIns/AppleUSBTCKeyboard.kext/

How to Load & Unload Kernel Extensions in OS X
ASCII.jp:不要なドライバーをスッキリ整理、KEXT関連コマンドを知る (1/2)|Apple Geeks

外部キーボードの存在判定

あるスクリプトを実行すると,外部キーボードが接続されているか否かで内臓キーボードの有効/無効を適切に切り替えられると良いと考えました.

外部キーボードが接続されているかどうかの確認には,lsusbioreg などのコマンドが使用できそうでした(他にもっと良い方法がありそう...) 前者は重かったので,後者のioregを使うことにしました.
以下の質問サイトの回答を拝借し,USB接続されているデバイス名一覧を表示 & 外部キーボード名を grep & 結果が空文字か判定することで,外部キーボードの接続有無を判定することにします.
List USB devices on OSX command line - Ask Different
最終的なスクリプトは以下です.

#!/bin/sh

IS_CONNECTED=`ioreg -p IOUSB -w0 | sed 's/[^o]*o //; s/@.*$//' | grep -v '^Root.*' | grep "USB Keyboard"` 
IS_LOADED=`kextstat -a | grep AppleUSBTCKeyboard`
if [ -n "${IS_CONNECTED}" ]; then
    if [ -n "${IS_LOADED}" ]; then
        `echo "your passowrd" | sudo -S kextunload /System/Library/Extensions/AppleUSBTopCase.kext/Contents/PlugIns/AppleUSBTCKeyboard.kext/`
    fi
else
    if [ -z "${IS_LOADED}" ]; then
        `echo "your password" | sudo -S kextload /System/Library/Extensions/AppleUSBTopCase.kext/Contents/PlugIns/AppleUSBTCKeyboard.kext/`
   fi
fi

キーボードの存在判定のために grep している部分は "USB Keyboard" としてますが,これは自分の使用しているキーボードが ThinkPad Compact USB Keyboard with TrackPoint であるためです.
パスワードを直接記述しているので,セキュリティ的な問題があります.また,シェルスクリプトに関しては初心者なので,見苦しいコードになっているかもしれません.

自動化

できれば,キーボード接続時/取り外し時に自動的に上記のスクリプトを実行してくれると良いです.これを実現するために launchd を活用しました.

LaunchAgent に登録して、スクリプトを自動起動する - それマグで!
Backups With Rsync and Launchd - Stuff… And Things…
Logging with launchd | Erik's Lab
LaunchDaemons (launchctl, launchd.plist) の使い方 - maruko2 Note.

先ほど書いたスクリプトを toggleInternalKeyboard.sh として /usr/local/bin 配下に配置し,以下のような plist ファイルを作成しました.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
          "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>Label</key>
    <string>com.example.toggleInternalKeyboard</string>
    <key>ProgramArguments</key>
    <array>
      <string>/usr/local/bin/toggleInternalKeyboard.sh</string>
    </array>
    <key>StartInterval</key>
    <integer>1</integer>
    <key>RunAtLoad</key>
    <true/>
    <key>StandardOutPath</key>
    <string>/var/log/toggleInternalKeyboard_output.log</string>
    <key>StandardErrorPath</key>
    <string>/var/log/toggleInternalKeyboard_err.log</string>
  </dict>
</plist>

<key>Label</key><string> 内の値で,デーモンの識別子を定義しています.
ProgramArguments で実行するスクリプトを指定しています.
StartInterval で1秒ごとにスクリプトを実行しています.
また,StandardOutputPathStandardErrorPath で,ログの出力先を指定しています.

上記の plist を /System/Library/LaunchDaemons/ 配下に配置します.
起動するには以下のコマンドを実行します.-w オプションを付加することで,OSブート時に自動的に起動するようにします.

$ sudo launchctl load -w /Library/LaunchDaemons/com.example.toggleInternalKeyboard.plist

停止させたいときは unload します.

$ sudo launchctl unload -w /Library/LaunchDaemons/com.example.toggleInternalKeyboard.plist

通知

ただでさえ反映までにラグがあるのに,通知も何もないとどのタイミングで切り替わったかがわかりません.切り替えた時に通知が来ると良い感じです.手軽に通知をとばすためには Apple Script を使用するのが良さそうでした.
例えば,以下のような単純な Apple Script でとりあえず通知を飛ばすことができるようです.

display notification "test" with title "TEST"

Apple Script はコマンドラインから osascript コマンドを通して実行できます.しかし,自分の環境では以下のようなエラーが出力されました.

$ osascript -e 'display notification "test" with title "TEST"'
2016-10-11 21:36:45.910 osascript[77739:1943672] NSNotificationCenter connection invalid

友人の Yosemite の環境では問題がなかったので,Sierra が悪いのかもしれないですが,詳細は不明です.

2016/10/27追記
私は tmux を使用していたのですが,tmux を抜けたところ上記エラーが出力されなくなりました.@q4yuu さん,ありがとうございました.以下の記事は上記のエラーが解決しなかった場合について記述しています.今後修正するかもしれません.

仕方がないので,無効化した場合/有効化した場合のための二種類の通知用 app を用意することにしました.

display notification "内部キーボードを有効化しました" with title "toggleInternalKeyboard"
display notification "内部キーボードを無効化しました" with title "toggleInternalKeyboard"

app の出力は,Script Editor の File > Export... から, File Format を Application にして保存するとできます.これらをとりあえず /usr/local/bin に配置しました.
最終的なスクリプトは以下です.

#!/bin/sh

IS_CONNECTED=`ioreg -p IOUSB -w0 | sed 's/[^o]*o //; s/@.*$//' | grep -v '^Root.*' | grep "USB Keyboard"` 
IS_LOADED=`kextstat -a | grep AppleUSBTCKeyboard`
if [ -n "${IS_CONNECTED}" ]; then
    if [ -n "${IS_LOADED}" ]; then
        `echo "your password" | sudo -S kextunload /System/Library/Extensions/AppleUSBTopCase.kext/Contents/PlugIns/AppleUSBTCKeyboard.kext/`
        `open /usr/local/bin/notifyDisableInternalKeyboard.app`
    fi
else
    if [ -z "${IS_LOADED}" ]; then
        `echo "your passowrd" | sudo -S kextload /System/Library/Extensions/AppleUSBTopCase.kext/Contents/PlugIns/AppleUSBTCKeyboard.kext/`
        `open /usr/local/bin/notifyEnableInternalKeyboard.app`
   fi
fi

これで,外部キーボードの接続/取り外しに合わせて,内臓キーボードを有効/無効にできるようになりました.

15
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
dwango
Born in the net, Connected by the net.

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
15
Help us understand the problem. What is going on with this article?