動機
ZoomやMicrosoft Teamsでのオンランミーティングが仕事や生活の一部になりました。操作にはずいぶん慣れましたが、とくにマイクのミュート、アンミュートは頻繁に使う機能です。話の隙間を狙ってアンミュートしようと、カーソルをマイクコントロールアイコンの上にのせてタイミングを待つマウスの上の手がつらい。
ボタン一発でマイクやカメラのOn-Offができるものがあればいいのに。
あればいい、なら作ってみたら?ということで引き出しに入りっぱなしだったAdafruit Circuit Playground Express(CPX)を引っ張り出して活躍してもらうことにしました。
しくみ
CPXからキーボードショートカットをパソコンに送出するという仕掛けです。今の状態を表すために、Neopixelがついたり消えたりするようにもしました。(On-Offどちらも同じショートカットでトグルさせているだけなので、NeopixelのOn-Off状態と合わせるために、最初にパソコン側でマイクとカメラをOffにしてから使い始めるという、”なんちゃって仕様”です。CPXをキーボードとして使っているのだけなので、パソコン側の今の状態を引き出すことはできないのです。できるともっといいのですが。今回は今すぐほしい、を優先しました。)
windowsとmacとではショートカットキーの組み合わせが違うので、CPXのスライドスイッチでどちらで使うのかを切り替えることができるようにしました。
Windowsでのショートカットキー
- microphone: Alt + A
- camera: Alt + V
Macでのショートカットキー
- microphone: Command + Shift + A
- camera: Command + Shift + V
見た目はこんな感じ
左がマイク用のAボタン、右がカメラ用のBボタンです。真ん中下にあるのがスライドスイッチで、この個体ではWindows用、Mac用を切り替えられるようにしてあります。(もう一つの個体ではZoomとMicrosoft Teamsとを切り替えられるようにしました)
Neopixelで今の状態をお知らせ。左(赤)がマイク、右(青)がカメラ。点灯がunmute (on)を表す。
動作の様子
code
Circuitpythonで書きました。Neopixelとbuttonの部分がうまく動くのを確認した後、スライドスイッチの部分を書き足そうと、adafruit_circuitplayground
libを読み込んでエラー。少々混乱しましたが、何とか書けました。
import board
import time
import usb_hid
import adafruit_fancyled.adafruit_fancyled as fancy
from digitalio import DigitalInOut, Direction, Pull
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keycode import Keycode
from adafruit_circuitplayground import cp
# cp.switch: left=True, right=False
# left: windows
# right: mac
# Zoom/Windows
# toggle microphone: Alt + A
# toggle camera: Alt + V
# Zoom/Mac
# toggle microphone: Cmd + Shift + A
# toggle camera: Cmd + Shift + V
# Set up a keyboard device.
kbd = Keyboard(usb_hid.devices)
# colors
mic_color = fancy.CHSV(0, 1.0, 0.01).pack() # hue, saturation, value
cam_color = fancy.CHSV(0.6, 1.0, 0.01).pack() # hue, saturation, value
# neopixel on cpx
npx = cp.pixels
# neopixel hue demo
i = 0
while i < 1:
for pp in range(10):
h = (pp * (1.0/10) + i) % 1.0
hsvcolor = fancy.CHSV(h, 1.0, 0.01) # hue, saturation, value
npx[pp] = hsvcolor.pack()
npx.show()
time.sleep(0.03)
i = i + 0.1
# off all
npx.fill((0, 0, 0))
npx.show()
# previous status
mic_status = False
cam_status = False
def neopix_control(idxs, rgb):
for i in idxs:
npx[i] = rgb # set with CHSV().pack(), brigntness included
npx.show()
while True:
# when button pressed
if cp.button_a:
if cp.switch: # True=Left=Windows
kbd.send(Keycode.ALT, Keycode.A) # --- windows
else: # False=Right=Mac
kbd.send(Keycode.COMMAND, Keycode.SHIFT, Keycode.A) # --- mac
if mic_status: # was on. turn it off
neopix_control([1, 2, 3], (0, 0, 0))
else: # was off. turn it on
neopix_control([1, 2, 3], mic_color)
# toggle status
mic_status = not mic_status
while cp.button_a:
pass
if cp.button_b:
if cp.switch: # True=Left=Windows
kbd.send(Keycode.ALT, Keycode.V) # --- windows
else: # False=Right=Mac
kbd.send(Keycode.COMMAND, Keycode.SHIFT, Keycode.V) # --- mac
if cam_status: # was on. turn it off
neopix_control([6, 7, 8], (0, 0, 0))
else: # was off. turn it on
neopix_control([6, 7, 8], cam_color)
# toggle status
cam_status = not cam_status
while cp.button_b:
pass
使ってみて
便利。
buttonがdebounceで複数押しになってしまうことがあるので、debounce対策をコードにいれるべき。
CPXのpinoutはいくつかがtouch sensorとしても使えるので、二つのボタンにとどまらず、もっとショートカットをアサインしてさらに便利にしたいと思っています。スクリーンシェアの切り替えや、ホスト以外をミュートなど、キーボードショートカットのあるものならなんでもできるハズ。家族にも聞いて必要なものを組み込んで使ってみます。
Zoom, Teams切り替えバージョン(Windows専用)も作って使っています。