iT邦幫忙

0

MacOS讀取藍牙搖桿訊號,利用python修改pynput程式碼實現 - 2.研究 pynput

  • 分享至 

  • xImage
  •  

請參考之前的文章:第一篇

4. 研究 pynput

首先,在Visual Studio Code界面中,將滑鼠移動到from pynput.keyboard import Listener,同時按下Macbook的command按鍵,就會出現超聯結的鼠標,點擊之後就可以看到pynput.keyboard的程式碼了。(內心os:之前我都是靠故意寫錯代碼,然後在終端機報錯欄給的超聯結進入import的module,不但麻煩而且很不方便)

進入pynput.keyboard之後可以看到:

from pynput._util import backend, Events

backend = backend(__name__)
KeyCode = backend.KeyCode
Key = backend.Key
Controller = backend.Controller
Listener = backend.Listener
del backend

Listener = backend.Listener 就是我們要找的,這個時候如果將__name__ print出來,就會發現是pynput.keyboard。接著繼續看pynput._util的程式碼

def backend(package):
    """Returns the backend module for a package.

    :param str package: The package for which to load a backend.
    """
    backend_name = os.environ.get(
        'PYNPUT_BACKEND_{}'.format(package.rsplit('.')[-1].upper()),
        os.environ.get('PYNPUT_BACKEND', None))
    if backend_name:
        modules = [backend_name]
    elif sys.platform == 'darwin':
        modules = ['darwin']
    elif sys.platform == 'win32':
        modules = ['win32']
    else:
        modules = ['xorg']

    errors = []
    resolutions = []
    for module in modules:
        try:
            return importlib.import_module('._' + module, package)
        except ImportError as e:
            errors.append(e)
            if module in RESOLUTIONS:
                resolutions.append(RESOLUTIONS[module])

    raise ImportError('this platform is not supported: {}'.format(
        '; '.join(str(e) for e in errors)) + ('\n\n'
            'Try one of the following resolutions:\n\n'
            + '\n\n'.join(
                ' * {}'.format(s)
                for s in resolutions))
            if resolutions else '')

我們將package print出來,發現還是pynput.keyboard
我們將sys.platform print出來,可以得到darwin
我們將'._' + module, package print出來,可以得到._darwin pynput.keyboard

上面這一段代碼,最後會return importlib.import_module('._' + module, package)
這是什麼意思研究很久也沒有結論,只能猜測應該是要import pynput.keyboard._darwin

接著我們進去pynput.keyboard._darwin看看,不過由於裡面的程式碼有點複雜,我不太會分析,所以只好利用插入大量的print,個人習慣是print(111) print(222) print(333)……,接著看看程式在執行的時候,自己插入的哪些段落有被print出來,就可以反推出有哪些程式碼被執行過,以下就是找到的結果:

class Listener(ListenerMixin, _base.Listener):
    # 省略多行程式碼
    def _handle(self, _proxy, event_type, event, _refcon):
        # 省略多行程式碼
        elif event_type == Quartz.NSSystemDefined:
        sys_event = Quartz.NSEvent.eventWithCGEvent_(event)
        if sys_event.subtype() == kSystemDefinedEventMediaKeysSubtype:
            # The key in the special key dict; True since it is a media
            # key
            key = ((sys_event.data1() & 0xffff0000) >> 16, True)
            if key in self._SPECIAL_KEYS:
                flags = sys_event.data1() & 0x0000ffff
                is_press = ((flags & 0xff00) >> 8) == 0x0a
                if is_press:
                    self.on_press(self._SPECIAL_KEYS[key])
                else:
                    self.on_release(self._SPECIAL_KEYS[key])

讀到這裡,我們就可以知道pynput是藉由importQuartz來讀取藍牙的訊號
我們將sys_event print出來,可以看到:

NSEvent: type=SysDefined loc=(266.629,634.41) time=232454.5 flags=0 win=0x0 winNum=0 ctxt=0x0 subtype=8 data1=1051392 data2=-1
NSEvent: type=SysDefined loc=(266.629,634.41) time=232454.5 flags=0 win=0x0 winNum=0 ctxt=0x0 subtype=8 data1=1182208 data2=-1
NSEvent: type=SysDefined loc=(266.629,634.41) time=232454.8 flags=0 win=0x0 winNum=0 ctxt=0x0 subtype=8 data1=1182464 data2=-1
NSEvent: type=SysDefined loc=(266.629,634.41) time=232454.8 flags=0 win=0x0 winNum=0 ctxt=0x0 subtype=8 data1=1051136 data2=-1

觀察可以發現只有data1才有變化
接著我將藍牙搖桿的四個搖桿方向,以及其他6個鍵盤會接收到data1值做整理,如下:
https://ithelp.ithome.com.tw/upload/images/20220130/20141667uWq3rERRg7.png
整理後發現

# 上下左右,前上前下,ABCD都會出現
1051392
1051136
# 上 單獨出現
1182208
1182464
# 下 單獨出現
1116672
1116928
# 左 單獨出現
1313280
1313536
# 右 單獨出現
1247744
1248000

續看,請參考:第三篇


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言