import pyautogui import ctypes import time import win32gui, win32con from pyvda import VirtualDesktop, get_virtual_desktops import subprocess class WhaleTranslator: def __init__(self, app, logger, secret_mode=True, vd_mode=False): self.app = app self.logger = logger self.vd_mode = vd_mode self.newtab = "about:newtab" isSecret = secret_mode if isSecret: self.whale_window_name = "새 시크릿 탭 - Whale" else: self.whale_window_name = "새 탭 - Whale" self.whale_hwnd = None if self.vd_mode: self.ensure_virtual_desktop_2_exists() self.start_whale_browser() if self.vd_mode: self.return_to_virtual_desktop_1() def start_whale_browser(self): # Whale 브라우저 실행 whale_path = r"C:\\Program Files\\Naver\\Naver Whale\\Application\\whale.exe" # whale.exe 경로 지정 # 웨일을 시크릿 모드로 실행 subprocess.Popen([whale_path, '--incognito']) self.find_whale_window() pyautogui.hotkey('ctrl', 'l') # 혹은 'ctrl', 'shift'를 사용할 수도 있음 """입력기를 영어로 전환한 후 pyautogui로 URL 입력""" # 입력기를 영어로 전환 (한영 전환키 사용) self.switch_language() time.sleep(0.3) pyautogui.typewrite(self.newtab) # subprocess.Popen(["C:\\Program Files\\Naver\\Naver Whale\\Application\\whale.exe", '--incognito']) # 경로 확인 필요 # 창 크기 조정 time.sleep(2) # 창이 뜰 때까지 대기 hwnd = win32gui.FindWindow(None, self.whale_window_name) # Whale 브라우저 창 이름 if hwnd: win32gui.ShowWindow(hwnd, win32con.SW_NORMAL) win32gui.SetWindowPos(hwnd, None, 0, 0, 1920, 1080, win32con.SWP_NOZORDER) else: self.logger.debug("Whale 창을 찾을 수 없습니다.") def find_whale_window(self): """웨일 창 핸들을 찾는 메서드""" if not self.whale_hwnd: self.whale_hwnd = self.find_window_by_title(self.whale_window_name) return self.whale_hwnd def find_window_by_title(self, window_name): def enum_windows_callback(hwnd, result): if win32gui.IsWindowVisible(hwnd) and window_name in win32gui.GetWindowText(hwnd): result.append(hwnd) result = [] win32gui.EnumWindows(enum_windows_callback, result) return result[0] if result else None def ensure_virtual_desktop_2_exists(self): """가상 데스크톱 2가 존재하는지 확인하고, 없으면 생성""" try: # 현재 활성화된 가상 데스크톱 수 확인 desktops = get_virtual_desktops() number_of_desktops = len(desktops) # 가상 데스크톱 2가 존재하지 않으면 생성 if number_of_desktops < 2: pyautogui.hotkey('win', 'ctrl', 'd') # 새 가상데스크탑 생성 self.logger.debug("가상 데스크톱 2가 생성되었습니다.") time.sleep(1) else: self.switch_to_virtual_desktop_2() self.close_whale_window_if_exists() self.logger.debug("가상 데스크톱 2가 이미 존재합니다.") except Exception as e: self.logger.debug(f"가상 데스크톱 확인/생성 중 오류 발생: {e}") def switch_to_whale(self): """웨일로 포커스 전환""" if self.whale_hwnd: win32gui.ShowWindow(self.whale_hwnd, win32con.SW_RESTORE) win32gui.SetForegroundWindow(self.whale_hwnd) self.logger.debug('크롬 창으로 포커스 이동.') else: self.logger.debug('크롬 창을 찾을 수 없습니다.') def switch_to_virtual_desktop_2(self): """가상 데스크톱 2로 전환""" try: VirtualDesktop(2).go() self.logger.debug("가상 데스크톱 2로 전환되었습니다.") time.sleep(1) except Exception as e: self.logger.debug(f"가상 데스크톱 전환 중 오류 발생: {e}") def return_to_virtual_desktop_1(self): """가상 데스크톱 1로 복귀""" try: VirtualDesktop(1).go() self.logger.debug("가상 데스크톱 1로 전환되었습니다.") time.sleep(1) except Exception as e: self.logger.debug(f"가상 데스크톱 전환 중 오류 발생: {e}") def translate_image(self, url): if self.vd_mode: self.switch_to_virtual_desktop_2() if self.find_whale_window(): win32gui.ShowWindow(self.whale_hwnd, win32con.SW_RESTORE) # 웨일 창 활성화 win32gui.SetForegroundWindow(self.whale_hwnd) pyautogui.moveTo(960,580) # 마우스 센터로 이동 pyautogui.hotkey('ctrl', 'l') # 웨일 브라우저의 주소창으로 이동 self.enter_url(url) time.sleep(1) # page Loading pyautogui.rightClick() time.sleep(0.2) # 컨텍스트 메뉴 대기 pyautogui.press('c') # 번역된 이미지 클립보드에 복사 time.sleep(1) # 이미지 로딩 대기 pyautogui.rightClick() time.sleep(0.2) # 컨텍스트 메뉴 대기 pyautogui.press('r') # 번역 클릭 time.sleep(7) # 번역 완료 대기 pyautogui.rightClick() time.sleep(0.2) # 컨텍스트 메뉴 대기 pyautogui.press('c') # 번역된 이미지 클립보드에 복사 pyautogui.hotkey('ctrl', 'l') # 새 탭으로 이동 pyautogui.typewrite(self.newtab) # URL을 입력 self.enter_url(self.newtab) self.logger.debug(f'번역 완료: {url}') if self.vd_mode: self.return_to_virtual_desktop_1() else: self.logger.debug('웨일 창을 찾을 수 없습니다.') def switch_language(self): # Shift 키 누름 pyautogui.keyDown('shift') # 0.1초 대기 후 Alt 키 누름 time.sleep(1) pyautogui.keyDown('alt') # 0.5초 대기 time.sleep(1) # Alt 키 해제 pyautogui.keyUp('alt') # Shift 키 해제 pyautogui.keyUp('shift') def set_input_language(self, lang='EN'): # 윈도우에서 입력 언어를 변경하는 코드 # lang='EN' 또는 lang='KR'을 설정 가능 user32 = ctypes.WinDLL('user32', use_last_error=True) if lang == 'EN': # 영어로 변경 user32.LoadKeyboardLayoutW('00000409', 1) elif lang == 'KR': # 한글로 변경 user32.LoadKeyboardLayoutW('00000412', 1) def enter_url(self, url): # 주소창에 URL 입력하기 전에 영어로 변경 # self.set_input_language('EN') # time.sleep(0.5) # 입력 모드 전환 후 잠시 대기 # 주소창으로 이동 후 URL 입력 pyautogui.hotkey('ctrl', 'l') # 주소창으로 이동 time.sleep(0.5) pyautogui.typewrite(url) # URL 입력 pyautogui.press('enter',) # Enter 키 입력 time.sleep(1) # 페이지 로딩 대기 def close_whale_window_if_exists(self): """'새 탭 - Whale' 창이 존재하면 종료""" """'새 시크릿 탭 - Whale' 창이 존재하면 종료""" whale_window_name = "새 탭 - Whale" sec_whale_window_name = "새 시크릿 탭 - Whale" whale_hwnd = self.find_window_by_title(whale_window_name) sec_whale_hwnd = self.find_window_by_title(sec_whale_window_name) if whale_hwnd: self.logger.debug(f"'{whale_window_name}' 창을 찾았습니다. 종료 중...") win32gui.PostMessage(whale_hwnd, win32con.WM_CLOSE, 0, 0) # 창을 종료하는 메시지 전송 time.sleep(1) self.logger.debug(f"'{whale_window_name}' 창을 종료했습니다.") elif sec_whale_hwnd: self.logger.debug(f"'{sec_whale_window_name}' 창을 찾았습니다. 종료 중...") win32gui.PostMessage(sec_whale_hwnd, win32con.WM_CLOSE, 0, 0) # 창을 종료하는 메시지 전송 time.sleep(1) self.logger.debug(f"'{sec_whale_window_name}' 창을 종료했습니다.") else: self.logger.debug(f"'{whale_window_name}' 또는 '{sec_whale_window_name}' 창을 찾지 못했습니다.") def close_all_virtual_desktops(self): """모든 가상 데스크톱을 종료""" try: desktops = get_virtual_desktops() number_of_desktops = len(desktops) # 가상 데스크톱이 1개 이상일 때만 종료 while number_of_desktops > 1: self.close_whale_window_if_exists() # 웨일 브라우저 창이 있으면 종료 pyautogui.hotkey('win', 'ctrl', 'f4') # 현재 가상 데스크톱 닫기 time.sleep(1) # 각 데스크톱 닫기 사이에 짧은 대기시간 추가 desktops = get_virtual_desktops() number_of_desktops = len(desktops) self.logger.debug(f"남은 가상 데스크톱 수: {number_of_desktops}") self.logger.debug("모든 가상 데스크톱이 종료되었습니다.") except Exception as e: self.logger.debug(f"가상 데스크톱 종료 중 오류 발생: {e}")