Skip to content

Commit 5dc3979

Browse files
authored
Merge pull request #32 from tangflash/feature/chinese-app-name-support
Feature/improve Chinese app name support in Launch-Tool and Resize-Tool
2 parents f117c07 + 943e0b9 commit 5dc3979

File tree

2 files changed

+99
-21
lines changed

2 files changed

+99
-21
lines changed

main.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,25 @@ def type_tool(loc:list[int],text:str,clear:bool=False,press_enter:bool=False)->s
126126
if clear=='True':
127127
pg.hotkey('ctrl','a')
128128
pg.press('backspace')
129-
pg.typewrite(text,interval=0.1)
129+
130+
# Check if text contains non-ASCII characters (like Chinese)
131+
if any(ord(char) > 127 for char in text):
132+
# Use clipboard method for non-ASCII characters
133+
# Store current clipboard content
134+
original_clipboard = pc.paste()
135+
try:
136+
# Copy text to clipboard and paste it
137+
pc.copy(text)
138+
pg.sleep(0.1) # Small delay to ensure clipboard is updated
139+
pg.hotkey('ctrl','v')
140+
finally:
141+
# Restore original clipboard content
142+
pg.sleep(0.1)
143+
pc.copy(original_clipboard)
144+
else:
145+
# Use normal typewrite for ASCII characters
146+
pg.typewrite(text,interval=0.1)
147+
130148
if press_enter:
131149
pg.press('enter')
132150
return f'Typed {text} on {control.Name} Element with ControlType {control.ControlTypeName} at ({x},{y}).'

src/desktop/__init__.py

Lines changed: 80 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)