請參考之前的文章:第一篇
首先,在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值做整理,如下:
整理後發現
# 上下左右,前上前下,ABCD都會出現
1051392
1051136
# 上 單獨出現
1182208
1182464
# 下 單獨出現
1116672
1116928
# 左 單獨出現
1313280
1313536
# 右 單獨出現
1247744
1248000
續看,請參考:第三篇