@@ -79,23 +79,59 @@ def get_apps_from_start_menu(self)->dict[str,str]:
7979
8080 def execute_command (self ,command :str )-> tuple [str ,int ]:
8181 try :
82- result = subprocess .run (['powershell' , '-Command' ]+ command .split (),
83- capture_output = True , check = True )
84- return (result .stdout .decode ('latin1' ),result .returncode )
82+ # Use UTF-8 encoding for better Chinese character support
83+ result = subprocess .run (
84+ ['powershell' , '-NoProfile' , '-Command' ,
85+ '[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; ' + command ],
86+ capture_output = True , check = True , text = True , encoding = 'utf-8'
87+ )
88+ return (result .stdout , result .returncode )
8589 except subprocess .CalledProcessError as e :
86- return (e .stdout .decode ('latin1' ),e .returncode )
90+ try :
91+ # Try UTF-8 first
92+ error_output = e .stdout if hasattr (e , 'stdout' ) and e .stdout else ''
93+ return (error_output , e .returncode )
94+ except :
95+ # Fallback to GBK for Chinese Windows systems
96+ try :
97+ result = subprocess .run (
98+ ['powershell' , '-NoProfile' , '-Command' , command ],
99+ capture_output = True , check = False
100+ )
101+ return (result .stdout .decode ('gbk' , errors = 'ignore' ), result .returncode )
102+ except :
103+ return ('Command execution failed with encoding issues' , 1 )
87104
88105 def is_app_browser (self ,node :Control ):
89106 process = Process (node .ProcessId )
90107 return process .name () in BROWSER_NAMES
91108
92109 def resize_app (self ,name :str ,size :tuple [int ,int ]= None ,loc :tuple [int ,int ]= None )-> tuple [str ,int ]:
93110 apps = self .get_apps ()
94- matched_app :tuple [App ,int ]| None = process .extractOne (name ,apps ,score_cutoff = 70 )
111+
112+ # Improved fuzzy matching for Chinese and English app names
113+ # First try exact match (case insensitive)
114+ exact_matches = [app for app in apps if name .lower () in app .name .lower () or app .name .lower () in name .lower ()]
115+ matched_app = None
116+
117+ if exact_matches :
118+ matched_app = exact_matches [0 ]
119+ else :
120+ # If no exact match, use fuzzy matching with lower threshold for Chinese
121+ fuzzy_match = process .extractOne (name , apps , score_cutoff = 60 )
122+ if fuzzy_match :
123+ matched_app , _ = fuzzy_match
124+ else :
125+ # Try partial matching for Chinese characters
126+ for app in apps :
127+ if any (char in app .name for char in name ) or any (char in name for char in app .name ):
128+ matched_app = app
129+ break
130+
95131 if matched_app is None :
96132 return (f'Application { name .title ()} not open.' ,1 )
97- app , _ = matched_app
98- app_control = ControlFromHandle (app .handle )
133+
134+ app_control = ControlFromHandle (matched_app .handle )
99135 if loc is None :
100136 x = app_control .BoundingRectangle .left
101137 y = app_control .BoundingRectangle .top
@@ -111,19 +147,43 @@ def resize_app(self,name:str,size:tuple[int,int]=None,loc:tuple[int,int]=None)->
111147
112148 def launch_app (self ,name :str )-> tuple [str ,int ]:
113149 apps_map = self .get_apps_from_start_menu ()
114- matched_app = process .extractOne (name ,apps_map ,score_cutoff = 80 )
115-
116- # TODO: Handle the case of understanding the language of the app name
117-
118- if matched_app is None :
119- return (f'Application { name .title ()} not found in start menu.' ,1 )
120- app_id ,_ ,app_name = matched_app
121- if app_id .endswith ('.exe' ):
122- _ ,status = self .execute_command (f'Start-Process "{ app_id } "' )
123- else :
124- _ ,status = self .execute_command (f'Start-Process "shell:AppsFolder\\ { app_id } "' )
125- response = f'Launched { name .title ()} . Wait for the app to launch...'
126- return response ,status
150+
151+ # Improved fuzzy matching for Chinese and English app names
152+ # First try exact match (case insensitive)
153+ exact_matches = {k : v for k , v in apps_map .items () if name .lower () in k .lower () or k .lower () in name .lower ()}
154+ if exact_matches :
155+ # Use the first exact match
156+ app_name = list (exact_matches .keys ())[0 ]
157+ app_id = exact_matches [app_name ]
158+ if app_id .endswith ('.exe' ):
159+ _ ,status = self .execute_command (f'Start-Process "{ app_id } "' )
160+ else :
161+ _ ,status = self .execute_command (f'Start-Process "shell:AppsFolder\\ { app_id } "' )
162+ response = f'Launched { name .title ()} . Wait for the app to launch...'
163+ return response ,status
164+
165+ # If no exact match, use fuzzy matching with lower threshold for Chinese
166+ matched_app = process .extractOne (name ,apps_map ,score_cutoff = 60 )
167+ if matched_app is not None :
168+ app_id ,_ ,app_name = matched_app
169+ if app_id .endswith ('.exe' ):
170+ _ ,status = self .execute_command (f'Start-Process "{ app_id } "' )
171+ else :
172+ _ ,status = self .execute_command (f'Start-Process "shell:AppsFolder\\ { app_id } "' )
173+ response = f'Launched { name .title ()} . Wait for the app to launch...'
174+ return response ,status
175+
176+ # Try partial matching for Chinese characters
177+ for app_name , app_id in apps_map .items ():
178+ if any (char in app_name for char in name ) or any (char in name for char in app_name ):
179+ if app_id .endswith ('.exe' ):
180+ _ ,status = self .execute_command (f'Start-Process "{ app_id } "' )
181+ else :
182+ _ ,status = self .execute_command (f'Start-Process "shell:AppsFolder\\ { app_id } "' )
183+ response = f'Launched { name .title ()} . Wait for the app to launch...'
184+ return response ,status
185+
186+ return (f'Application { name .title ()} not found in start menu. Available apps with similar names: { list (apps_map .keys ())[:5 ]} ' ,1 )
127187
128188 def switch_app (self ,name :str )-> tuple [str ,int ]:
129189 apps = {app .name :app for app in self .desktop_state .apps }
0 commit comments