1- import os
1+ import argparse
2+ import asyncio
23import logging
4+ import os
35
46from importlib .machinery import SourceFileLoader
57
8+ from joycontrol import logging_default as log , utils
9+ from joycontrol .controller import Controller
10+ from joycontrol .memory import FlashMemory
11+ from joycontrol .protocol import controller_protocol_factory
12+ from joycontrol .server import create_hid_server
13+
614logger = logging .getLogger (__name__ )
715
8- def load_plugin (plugin , controller_state , * plugin_options ):
9- logger .info (f'Loading: { plugin } ' )
10- module = SourceFileLoader (plugin , plugin ).load_module ()
11- plugin_name = os .path .splitext (os .path .basename (plugin ))[0 ]
12- joycontrol_plugin = module .__dict__ [plugin_name ](controller_state , * plugin_options )
13- return joycontrol_plugin
16+ class PluginLoader :
17+ def __init__ (self ):
18+ self .transport = None
19+
20+
21+ def __load_plugin (self , plugin , controller_state , * plugin_options ):
22+ logger .info (f'Loading: { plugin } ' )
23+ module = SourceFileLoader (plugin , plugin ).load_module ()
24+ plugin_name = os .path .splitext (os .path .basename (plugin ))[0 ]
25+ joycontrol_plugin = module .__dict__ [plugin_name ](controller_state , * plugin_options )
26+ return joycontrol_plugin
27+
28+
29+ async def start (self , args ):
30+ # Create memory containing default controller stick calibration
31+ spi_flash = FlashMemory ()
32+
33+ # Get controller name to emulate from arguments
34+ controller = Controller .from_arg ('PRO_CONTROLLER' )
35+
36+ with utils .get_output (path = None , default = None ) as capture_file :
37+ factory = controller_protocol_factory (controller , spi_flash = spi_flash )
38+ ctl_psm , itr_psm = 17 , 19
39+ transport , protocol = await create_hid_server (factory , reconnect_bt_addr = args .reconnect_bt_addr ,
40+ ctl_psm = ctl_psm ,
41+ itr_psm = itr_psm , capture_file = capture_file ,
42+ device_id = args .device_id )
43+
44+ controller_state = protocol .get_controller_state ()
45+ self .transport = transport
46+
47+ try :
48+ # waits until controller is fully connected
49+ await controller_state .connect ()
50+ joycontrol_plugin = self .__load_plugin (args .plugin , controller_state , args .plugin_options )
51+ await joycontrol_plugin .run ()
52+ except Exception as e :
53+ logger .error (e )
54+ finally :
55+ await transport .close ()
56+ self .transport = None
57+ self .joycontrol_cmd = None
58+
59+
60+ async def stop (self ):
61+ if self .transport :
62+ logger .info ('Stopping communication...' )
63+ self .transport = None
64+
65+
66+ def main ():
67+ # check if root
68+ if not os .geteuid () == 0 :
69+ raise PermissionError ('Script must be run as root!' )
70+
71+ parser = argparse .ArgumentParser ()
72+ parser .add_argument ('plugin' , type = str , help = 'joycontrol plugin path' )
73+ parser .add_argument ('-p' , '--plugin-options' , nargs = '*' , help = 'joycontrol plugin options' )
74+ parser .add_argument ('-d' , '--device_id' )
75+ parser .add_argument ('-r' , '--reconnect_bt_addr' , type = str , default = None ,
76+ help = 'The Switch console Bluetooth address, for reconnecting as an already paired controller' )
77+ parser .add_argument ('-v' , '--verbose' , action = 'store_true' )
78+ args = parser .parse_args ()
79+
80+ if args .verbose :
81+ log .configure ()
82+ else :
83+ log .configure (console_level = logging .INFO )
84+
85+ loop = asyncio .get_event_loop ()
86+ loader = PluginLoader ()
87+
88+ try :
89+ loop .run_until_complete (loader .start (args ))
90+ except KeyboardInterrupt :
91+ loop .run_until_complete (loader .stop ())
0 commit comments