Re: [問題] 2.4G 無線滑鼠鍵盤憑甚麼關我筆電?

看板Linux作者 (cuello)時間3年前 (2021/04/10 01:39), 編輯推噓6(605)
留言11則, 8人參與, 3年前最新討論串2/4 (看更多)
上一篇我所提的問題, 有了部份解答, 回文整理一下 我講的瑣碎一點, 大家比較容易發現我的盲點 以後有碰到類似問題的人也可以省下一點時間 搞不好, 最常跑來回顧細節的, 就是我自己 因為我們會游走在 "kernel 邊緣" (我現在是 5.10.28) 所以我們所討論的這些, 基本上 *應該要* 適用所有人 先大致複習一下有點複雜的問題 我有個無線滑鼠直鍵盤, 稱為 空中飛鼠 它身上長了一個電源鍵, 但是按下去會同時 1. 透過 IR LED 關掉電視 2. 透過 USB 關掉筆電 但是我不要它關我筆電... 前情提要: (抄過來) > 1. 它憑啥關我筆電?甚麼管道?我自己都還要 sudo, 它誰? > 2. 如何告訴我的系統,不准接受 hid 來的 shutdown 命令 =============================================== 我們從第二個問題開始, 再回到第一個問題 =============================================== 實務上, 會有不少人碰到類似的問題, 例如 USB 鍵盤右上角長了一顆電源鍵, 因為很接近常用鍵 動不動就會無意間按到, 導致無預警關機, 例如: https://i.stack.imgur.com/9EgBZ.jpg
也有人用的 USB HID 長的像這樣 https://www.orbsmart.de/wp-content/uploads/2018/09/orbsmart-WA-1_1-1.jpg
這比較像我這支所謂的 "空中飛鼠", 大概因為它有陀螺儀, 可以像玩 Wii 那樣在空中揮舞, 就帶動螢幕上的鼠標 https://i.imgur.com/7mJwOoi.jpg
另外, 要是有一天, 你突然發現機器是關機狀態, 不要排除是你家的貓, 這時也會想要 disable 那個鍵 或是, 有時會需要把 sleep/suspend/hibernate 鍵停用 https://i.stack.imgur.com/524Oj.jpg
最簡單的方法就是修改 /etc/systemd/logind.conf 把 HandlePowerKey=poweroff 改為 =ignore 或是把 HandleLidSwitch 改為 =ignore (...) (至於 /etc/acpi/.... 我到現在還是一頭霧水, 這中間大概也夾雜了一些過渡性的 kernel 問題 還有我的筆電硬體特別的狀況... 所以不想再去想了) 這是 Bencrie 一開始就想到的, 但是他也沒忘記有個前提 就是 *如果你用 systemd 的話*, 換句話說, 並不是所有人, 所有系統, 都可以從這邊著手 而且改 logind.conf 的話, 只能讓所有的電源鍵都失效. 因為它在很上層, 應該無法分辨 interrupt 是來自哪個電源鍵. 我的情形是, 最好只停用 "空中飛鼠" 的電源鍵 (不含 IR LED), 保留筆電上面電源鍵的功能. 我所能找到的是: 方法一, Vojtech Pavlik 寫的 evtest(1) 是個好朋友. ************************************************** (不是 xev(1), xinput(1), showkey(1)... 等, 選對工具是關鍵) $ sudo apt-get install evtest $ sudo evtest --grab # 需要 root, 要記得 --grab /dev/input/event0: AT Translated Set 2 keyboard (...) /dev/input/event12: Power Button <== 這兩個是筆電的電源鍵 /dev/input/event13: Power Button <== 但不知為何有兩個一樣的 (...) /dev/input/event18: FREEWAY TECHNOLOGY RFIC-MOUSE Keyboard /dev/input/event19: FREEWAY TECHNOLOGY RFIC-MOUSE Consumer Control /dev/input/event20: FREEWAY TECHNOLOGY RFIC-MOUSE System Control /dev/input/event21: FREEWAY TECHNOLOGY RFIC-MOUSE /dev/input/event22: FREEWAY TECHNOLOGY RFIC-MOUSE (...) Select the device event number [0-27]: 先確定想要停用的是哪一行的, 我要的是 "event20 ... System Control" 所以就打 "20", 然後那個電原鍵就已經沒用了... (直到 Ctrl-C) 下一個畫面如下: Input driver version is 1.0.1 Input device ID: bus 0x3 vendor 0x25a7 product 0x2402 version 0x101 Input device name: "FREEWAY TECHNOLOGY RFIC-MOUSE System Control" Supported events: Event type 0 (EV_SYN) Event type 1 (EV_KEY) Event code 116 (KEY_POWER) <==== 這個才是標的 Event code 139 (KEY_MENU) <---+ Event code 142 (KEY_SLEEP) <---+ 這三個我不懂, 沒反應... Event code 143 (KEY_WAKEUP) <---+ Event type 4 (EV_MSC) Event code 4 (MSC_SCAN) Properties: Testing ... (interrupt to exit) <-- 敲 Ctrl-C 結束 試按一下紅色 [電源鍵] Event: time 1617615928.788579, type 4 (EV_MSC), code 4 (MSC_SCAN), value 10081 Event: time 1617615928.788579, type 1 (EV_KEY), code 116 (KEY_POWER), value 1 Event: time 1617615928.788579, -------------- SYN_REPORT ------------ Event: time 1617615928.900571, type 4 (EV_MSC), code 4 (MSC_SCAN), value 10081 Event: time 1617615928.900571, type 1 (EV_KEY), code 116 (KEY_POWER), value 0 Event: time 1617615928.900571, -------------- SYN_REPORT ------------ ^C $ 按 Ctrl-C 出來之後就不要再按電源鍵了, 會關機的. 那~~~ 我是怎麼確定是 event20 的呢?是一個一個試出來的! 用 sudo evtest --grab 測試其實很方便, 因為 --grab 就是叫 evtest 把接到的 input event "據為己有", 或是換句話說, 讓這個 interrupt "到此為止", 不再傳播下去, 或"上去" 所以其它的 handlers 都不會知到發生過這個按鍵的動作. 所以, "空中飛鼠" 來的 poweroff event 就被攔截在一個很低的位階 不涉及 X, 或 WM, 或 desktop. NB 1: 最好不要去 --grab 那個 event0, 因為會不能打 Ctrl-C 只能由外面 ssh 進來 killall evtest. NB 2: 這時, 筆電跟空中飛鼠上其它所有的鍵似乎都沒受到影響. NB 3. 不能直接去移除不想要的 /dev/nput/event20, 沒有用的 因為它是 opened 的, 如果在另外一個 terminal 做 $ sudo fuser -v /dev/input/event20 會看到: USER PID ACCESS COMMAND /dev/input/event20: root 1 F.... systemd root 264 F.... systemd-logind 我 2860 F.... Xorg root 8679 f.... evtest 如果用另一個 evtest 的 instance, 會看到: $ sudo evtest /dev/input/event20 (...) *********************************************** This device is grabbed by another process. No events are available to evtest while the other grab is active. In most cases, this is caused by an X driver, try VT-switching and re-run evtest again. Run the following command to see processes with an open fd on this device "fuser -v /dev/input/event20" *********************************************** (...) 所以問題初步解決! 但是必須讓 evtest(1) 一直跑下去 讓它抓住這個按鍵 event, 丟到垃圾筒: $ sudo evtest --grab /dev/input/event20 >/dev/null 所以, 寫了一個小 script 來幫忙找到那個對的 device. 想試試看的人, 只要改一下 KEY 跟 NAME: ----- begin 我把它叫做 disable-airmouse-powerbtn ----- PROG=`basename -- "$0"` KEY="FREEWAY TECHNOLOGY RFIC-MOUSE System Control" NAME="KEY_POWER/空中飛鼠" FILE="/proc/bus/input/devices" EV=`grep -B1 -A7 "$KEY" "$FILE" | \ sed -ne 's/^H: .*\(\<[a-z0-9]*\).*$/\1/p'` if [ "$EV" ] then echo "# $PROG: got \"$EV\" from $FILE" else echo "*** $PROG: device of $NAME not found" exit 157 fi EVDEV="/dev/input/$EV" if [ "$1" = "do" ] then echo "# $PROG: sudo evtest --grab $EVDEV >/dev/null" sudo evtest --grab "$EVDEV" >/dev/null else echo "# $PROG: $NAME found as $EVDEV" echo "# $PROG: append \"do\" as argv1 to actually disable it" fi --- end of disable-airmouse-powerbtn --- 然後執行看看 $ disable-airmouse-powerbtn # disable-airmouse-powerbtn: got "event20" from /proc/bus/input/devices # disable-airmouse-powerbtn: KEY_POWER/空中飛鼠 found as /dev/input/event20 # disable-airmouse-powerbtn: append "do" as argv1 to actually disable it 或是直接特讓它到背景執行 (這是幾乎不消耗資源的): $ setsid disable-airmouse-powerbtn do 我不曉得有沒有必要 detach, 反正我是這麼做了 反正, 斬斷一切的牽連, 免得被循著 cgroup 追殺... 後來, 我又把它放到 crontab 裡 @reboot /我家/sh/disable-airmouse-powerbtn do & 感興趣的人, 我推薦下載 Vojtech Pavlik 的原始碼看看, $ apt-get source evtest 它只有一個單一的 .c 檔, 連個 .h 都沒有 $ gcc evtest.c # 確認 ok 之後意就隨你怎麼玩了 關鍵在 ioctl(fd, EVIOCGRAB, (void*)1); 我把必要的幾行盡量節省空間地濃縮為, 感興趣可直接 gcc: (credit --> Vojtech Pavlik) #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <linux/input.h> int main(int argc, char* argv[]) { struct input_event ev; char *device, name[256]; int fd_evdev, n_bytes; if ( NULL != argv[1] ) device = argv[1]; else { fprintf(stderr, "usage: %s </dev/input/eventX>\n", *argv); return EXIT_FAILURE; } if ( -1 == ( fd_evdev = open(device, O_RDONLY) ) ) { fprintf(stderr, "failed opening \"%s\": ", device); perror(""); return EXIT_FAILURE; } (void) ioctl(fd_evdev, EVIOCGNAME(sizeof(name)), name); printf("ioctl(fd_evdev, EVIOCGRAB, (void*)1)... "); if ( 0 == ioctl(fd_evdev, EVIOCGRAB, (void*)1) ) printf("SUCCESS\n"); else { printf("FAILURE\n"); return EXIT_FAILURE; } printf("grabbing \"%s\" at %s, Ctrl-C to quit\n", name, device); while (1) if ((n_bytes = read(fd_evdev, &ev, sizeof ev)) < sizeof ev) break; return EXIT_SUCCESS; } 另一方面, 從一開始, 我就一直有個沒說出來的願望 是一個模模糊糊, 長得大概像這樣的願望: 方法二, # echo "咒術" > "/sys/迴戰/../的/../路徑/unbind" ********************************************************* 就是, 徹底跟 "那一個" 按鍵解約的辦法 只是一直沒找到 (還是沒耐心找到), 但幾天前試了一下 只是, 結果很容易忘記, 要寫個 script 記錄下來 就像我們在寫 Makefile 當作是在做 documentation 一樣 因為 script 有點大, 我把他的輸出 paste 過來就好 裡面已經吐露了足夠多的細節 (這次以 Lid Switch 為例) $ unbind Lid # unbind: given keyword "Lid" # unbind: inspecting "/proc/bus/input/devices"... # unbind: unbinding "/dev/input/event10" # unbind: with full name "Lid Switch" # unbind: via "/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0D:00/driver/unbind" # unbind: agenda: echo -n "PNP0C0D:00" | sudo tee "/sys/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0D:00/driver/unbind" # unbind: append "do" in the comamnd line to carry it out # unbind: sudo fuser -v /dev/input/10 USER PID ACCESS COMMAND /dev/input/event10: root 261 F.... systemd-logind 或直接 $ unbind Lid do 之後, 面板開開關關就沒有效用了. 這樣, 我就不需要 logind.conf 改 logind.conf 了 因為, 那個檔案在更新的時候常會被"更新", 就又要寫個 script... 這樣, 是不是很美好....? 不, 發生了一個意外... 那就是, 雖然對於 "Lid Switch", 或是筆電上的電源鍵來說很好用 但是對我那支 "空中飛鼠" 不行! 因為它的好幾個 event handler 是綁在一起的, 我把它 unbind 掉 就會連 "空中飛鼠" 的其它按鍵都解約了.... :( -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 59.115.221.229 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/Linux/M.1617989996.A.946.html

04/10 07:00, 3年前 , 1F
感謝
04/10 07:00, 1F

04/10 09:36, 3年前 , 2F
好硬核啊...
04/10 09:36, 2F

04/10 10:41, 3年前 , 3F
看起來是南橋幫你註冊input fd,kernel也隨之生成相關
04/10 10:41, 3F

04/10 10:41, 3年前 , 4F
event
04/10 10:41, 4F

04/10 12:45, 3年前 , 5F
應該是算 systemd 設計上的不足,畢竟都它在處理的
04/10 12:45, 5F

04/10 12:46, 3年前 , 6F
config 沒辦法個別設定要不要反應 power button
04/10 12:46, 6F

04/10 12:46, 3年前 , 7F
至於遮斷 event20 我想應該可以用 udev rule 去處理
04/10 12:46, 7F

04/10 19:15, 3年前 , 8F
推解決方案
04/10 19:15, 8F

04/11 09:14, 3年前 , 9F
04/11 09:14, 9F

04/11 11:13, 3年前 , 10F
04/11 11:13, 10F

04/16 05:18, 3年前 , 11F
04/16 05:18, 11F
文章代碼(AID): #1WS95ib6 (Linux)
文章代碼(AID): #1WS95ib6 (Linux)