2022年9月6日 星期二

For python--一直keyboard.Events() get key卻出現「Can't connect to display ...... : b'Maximum number of clients reached」問題

最近在試python的key board event ( in ubuntu) ,code如下
---------------------------
...
...
    while(True):
        with keyboard.Events() as events:    
            try:
                # Block at most 0.1 second
                event = events.get(0.1)
                if event is None:
                    if axnCode=="STOP"  or  axnCode=="":
                        continue
                    lastStopCount+=1
                    if lastStopCount>=2 :
                        lastStopCount=0
                        axnCode="STOP"
                else:
                    print('Received event {}'.format(event))
                    if(event.key==keyboard.Key.esc):
                        break
                    lastStopCount=0
                    if(event.key==keyboard.Key.left ):
                        axnCode="LEFT"    
                    if(event.key==keyboard.Key.right ):
                        axnCode="RIGHT"                        
                    if(event.key==keyboard.Key.down ):
                        axnCode="DOWN"                                            
                    if(event.key==keyboard.Key.up ):
                        axnCode="UP"                                                                            
            except:
                print("unknown exception")
---------------------------
鍵盤動作(上下左右)訊息是很正常地捕捉到,閒置也正常反應出來,
真的是「get key取碼 一時爽,一直get key一直爽」
不過....
剛開始跑是沒問題,不過....幾秒後卻出現這樣的錯誤訊息
--------------------------------
Traceback (most recent call last):
  File "/usr/lib/python3.10/threading.py", line 1009, in _bootstrap_inner
    self.run()
  File "/home/....../.local/lib/python3.10/site-packages/pynput/_util/__init__.py", line 210, in run
    self._run()
  File "/home/....../.local/lib/python3.10/site-packages/pynput/keyboard/_xorg.py", line 545, in _run
    super(Listener, self)._run()
  File "/home/....../.local/lib/python3.10/site-packages/pynput/_util/xorg.py", line 383, in _run
    self._display_record = Xlib.display.Display()
  File "/home/....../.local/lib/python3.10/site-packages/Xlib/display.py", line 80, in __init__
    self.display = _BaseDisplay(display)
  File "/home/....../.local/lib/python3.10/site-packages/Xlib/display.py", line 62, in __init__
    display.Display.__init__(*(self, ) + args, **keys)
  File "/home/....../.local/lib/python3.10/site-packages/Xlib/protocol/display.py", line 129, in __init__
    raise error.DisplayConnectionError(self.display_name, r.reason)
Xlib.error.DisplayConnectionError: Can't connect to display ":10.0": b'Maximum number of clients reached'
---------------------------------
真的是想不通,明明只是read key,跟Display有什麼關係啊...
是有關係,畢竟pynput是要連接到xwin(xserver), 才能接收事件.所以會有connect問題
這時,才萬別想去改「/etc/X11/xorg.conf」.問題不在那裡
(而且ubuntu 22.04 預設是沒有xorg.conf,想要用 Xorg -configure產生Xorg.conf很多程序要做....我放棄了,但也好在沒產出 & 修改xorg.conf,不然又被誤導,走不少冤枉路了)
「所以,要改用別的python module來read key 嗎?」
「不用,只要一個小小的步驟就解決了」
------Before----
    while(True):
        with keyboard.Events() as events:    
            try:
                ...
                ...
            except:
               ....
-----After---
   with keyboard.Events() as events:    
        while(True):
             try:
                 ...
                 ...
             except:
               ....
-----------------------------
是的,就這麼簡單,如同c#對於using(.....)資源總是放在迴圈外,
python的「with」也請儘量放在while/for 外面,否則資源來不及回收就又open新的,那一定會入不敷出的