clipboard機能のパイプラインを接続
This commit is contained in:
@@ -734,6 +734,10 @@ class Config:
|
|||||||
SELECTED_TRANSLATION_COMPUTE_DEVICE = ValidatedProperty('SELECTED_TRANSLATION_COMPUTE_DEVICE', _compute_device_validator)
|
SELECTED_TRANSLATION_COMPUTE_DEVICE = ValidatedProperty('SELECTED_TRANSLATION_COMPUTE_DEVICE', _compute_device_validator)
|
||||||
SELECTED_TRANSCRIPTION_COMPUTE_DEVICE = ValidatedProperty('SELECTED_TRANSCRIPTION_COMPUTE_DEVICE', _compute_device_validator)
|
SELECTED_TRANSCRIPTION_COMPUTE_DEVICE = ValidatedProperty('SELECTED_TRANSCRIPTION_COMPUTE_DEVICE', _compute_device_validator)
|
||||||
|
|
||||||
|
# -- Clipboard control ---
|
||||||
|
ENABLE_COPY_TO_CLIPBOARD = ManagedProperty('ENABLE_COPY_TO_CLIPBOARD', type_=bool)
|
||||||
|
ENABLE_PASTE_FROM_CLIPBOARD = ManagedProperty('ENABLE_PASTE_FROM_CLIPBOARD', type_=bool)
|
||||||
|
|
||||||
def init_config(self):
|
def init_config(self):
|
||||||
# Read Only
|
# Read Only
|
||||||
self._VERSION = "3.3.1"
|
self._VERSION = "3.3.1"
|
||||||
@@ -997,6 +1001,8 @@ class Config:
|
|||||||
self._WEBSOCKET_SERVER = False
|
self._WEBSOCKET_SERVER = False
|
||||||
self._WEBSOCKET_HOST = "127.0.0.1"
|
self._WEBSOCKET_HOST = "127.0.0.1"
|
||||||
self._WEBSOCKET_PORT = 2231
|
self._WEBSOCKET_PORT = 2231
|
||||||
|
self._ENABLE_COPY_TO_CLIPBOARD = False
|
||||||
|
self._ENABLE_PASTE_FROM_CLIPBOARD = False
|
||||||
|
|
||||||
def load_config(self):
|
def load_config(self):
|
||||||
if os_path.isfile(self.PATH_CONFIG) is not False:
|
if os_path.isfile(self.PATH_CONFIG) is not False:
|
||||||
|
|||||||
@@ -396,6 +396,12 @@ class Controller:
|
|||||||
)
|
)
|
||||||
model.updateOverlayLargeLog(overlay_image)
|
model.updateOverlayLargeLog(overlay_image)
|
||||||
|
|
||||||
|
if config.ENABLE_COPY_TO_CLIPBOARD is True:
|
||||||
|
clipboard_message = self.messageFormatter("SEND", translation, message)
|
||||||
|
model.setCopyToClipboard(clipboard_message)
|
||||||
|
if config.ENABLE_PASTE_FROM_CLIPBOARD is True:
|
||||||
|
model.setPasteFromClipboard()
|
||||||
|
|
||||||
if model.checkWebSocketServerAlive() is True:
|
if model.checkWebSocketServerAlive() is True:
|
||||||
model.websocketSendMessage(
|
model.websocketSendMessage(
|
||||||
{
|
{
|
||||||
@@ -728,6 +734,12 @@ class Controller:
|
|||||||
)
|
)
|
||||||
model.updateOverlayLargeLog(overlay_image)
|
model.updateOverlayLargeLog(overlay_image)
|
||||||
|
|
||||||
|
if config.ENABLE_COPY_TO_CLIPBOARD is True:
|
||||||
|
clipboard_message = self.messageFormatter("SEND", translation, message)
|
||||||
|
model.setCopyToClipboard(clipboard_message)
|
||||||
|
if config.ENABLE_PASTE_FROM_CLIPBOARD is True:
|
||||||
|
model.setPasteFromClipboard()
|
||||||
|
|
||||||
if model.checkWebSocketServerAlive() is True:
|
if model.checkWebSocketServerAlive() is True:
|
||||||
model.websocketSendMessage(
|
model.websocketSendMessage(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ from models.overlay.overlay import Overlay
|
|||||||
from models.overlay.overlay_image import OverlayImage
|
from models.overlay.overlay_image import OverlayImage
|
||||||
from models.watchdog.watchdog import Watchdog
|
from models.watchdog.watchdog import Watchdog
|
||||||
from models.websocket.websocket_server import WebSocketServer
|
from models.websocket.websocket_server import WebSocketServer
|
||||||
|
from models.clipboard.clipboard import Clipboard
|
||||||
from utils import errorLogging, setupLogger
|
from utils import errorLogging, setupLogger
|
||||||
|
|
||||||
class threadFnc(Thread):
|
class threadFnc(Thread):
|
||||||
@@ -138,6 +139,7 @@ class Model:
|
|||||||
# default no-op callbacks for energy check functions
|
# default no-op callbacks for energy check functions
|
||||||
self.check_mic_energy_fnc: Callable[[float], None] = lambda v: None
|
self.check_mic_energy_fnc: Callable[[float], None] = lambda v: None
|
||||||
self.check_speaker_energy_fnc: Callable[[float], None] = lambda v: None
|
self.check_speaker_energy_fnc: Callable[[float], None] = lambda v: None
|
||||||
|
self.clipboard = Clipboard()
|
||||||
self._inited = True
|
self._inited = True
|
||||||
|
|
||||||
def ensure_initialized(self) -> None:
|
def ensure_initialized(self) -> None:
|
||||||
@@ -1201,4 +1203,27 @@ class Model:
|
|||||||
errorLogging()
|
errorLogging()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def setCopyToClipboard(self, text:str) -> bool:
|
||||||
|
self.ensure_initialized()
|
||||||
|
try:
|
||||||
|
if isinstance(self.clipboard, Clipboard):
|
||||||
|
self.clipboard.copy(text)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
except Exception:
|
||||||
|
errorLogging()
|
||||||
|
return False
|
||||||
|
|
||||||
|
def setPasteFromClipboard(self) -> bool:
|
||||||
|
self.ensure_initialized()
|
||||||
|
try:
|
||||||
|
if isinstance(self.clipboard, Clipboard):
|
||||||
|
return self.clipboard.paste()
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
except Exception:
|
||||||
|
errorLogging()
|
||||||
|
return False
|
||||||
|
|
||||||
model = Model()
|
model = Model()
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
import os
|
||||||
from subprocess import Popen, PIPE
|
from subprocess import Popen, PIPE
|
||||||
|
from psutil import process_iter
|
||||||
import openvr
|
import openvr
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -9,6 +11,10 @@ except ImportError:
|
|||||||
def printLog(data, *args, **kwargs):
|
def printLog(data, *args, **kwargs):
|
||||||
print(data, *args, **kwargs)
|
print(data, *args, **kwargs)
|
||||||
|
|
||||||
|
def checkSteamvrRunning() -> bool:
|
||||||
|
_proc_name = "vrmonitor.exe" if os.name == "nt" else "vrmonitor"
|
||||||
|
return _proc_name in (p.name() for p in process_iter())
|
||||||
|
|
||||||
# Windows-specific imports via ctypes will be used when focusing windows
|
# Windows-specific imports via ctypes will be used when focusing windows
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
import ctypes
|
import ctypes
|
||||||
@@ -117,11 +123,10 @@ def paste_via_pyautogui(countdown: int = 0) -> bool:
|
|||||||
printLog('pyautogui not installed. Install with: pip install pyautogui')
|
printLog('pyautogui not installed. Install with: pip install pyautogui')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
printLog(f'Give focus to the target input. Pasting in {countdown} seconds...')
|
|
||||||
for i in range(countdown, 0, -1):
|
for i in range(countdown, 0, -1):
|
||||||
print(i, end=' ', flush=True)
|
print(i, end=' ', flush=True)
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
printLog('\nSending Ctrl+V...')
|
|
||||||
try:
|
try:
|
||||||
# pyautogui.hotkey is a safe cross-platform way to send keys
|
# pyautogui.hotkey is a safe cross-platform way to send keys
|
||||||
pyautogui.hotkey('ctrl', 'v')
|
pyautogui.hotkey('ctrl', 'v')
|
||||||
@@ -132,8 +137,8 @@ def paste_via_pyautogui(countdown: int = 0) -> bool:
|
|||||||
|
|
||||||
|
|
||||||
class Clipboard:
|
class Clipboard:
|
||||||
def __init__(self, vr_mode: bool = True):
|
def __init__(self):
|
||||||
if not vr_mode:
|
if not checkSteamvrRunning():
|
||||||
self.app_name = None
|
self.app_name = None
|
||||||
else:
|
else:
|
||||||
openvr.init(openvr.VRApplication_Background)
|
openvr.init(openvr.VRApplication_Background)
|
||||||
@@ -156,6 +161,7 @@ class Clipboard:
|
|||||||
self.app_name = name
|
self.app_name = name
|
||||||
break
|
break
|
||||||
openvr.shutdown()
|
openvr.shutdown()
|
||||||
|
printLog(f"Clipboard initialized. SteamVR App Name: {self.app_name}")
|
||||||
|
|
||||||
def copy(self, message: str) -> bool:
|
def copy(self, message: str) -> bool:
|
||||||
"""Copy `message` to clipboard.
|
"""Copy `message` to clipboard.
|
||||||
@@ -179,18 +185,17 @@ class Clipboard:
|
|||||||
True if paste command was sent, False otherwise.
|
True if paste command was sent, False otherwise.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if window_name is None:
|
window_name = window_name if window_name is not None else self.app_name
|
||||||
window_name = self.app_name
|
|
||||||
|
|
||||||
# focus target window (Windows only) — window_name is required
|
# If window_name is provided, attempt to focus it (Windows only).
|
||||||
focused = False
|
# If window_name is None, skip focusing and paste into the currently focused window.
|
||||||
if sys.platform == 'win32':
|
if window_name is not None and sys.platform == 'win32':
|
||||||
if not window_name:
|
printLog(f"paste: attempting to focus window matching '{window_name}'")
|
||||||
printLog('paste: window_name is required on Windows')
|
focused = False
|
||||||
return False
|
|
||||||
|
|
||||||
# try title substring match first
|
# try title substring match first
|
||||||
wins = find_windows_by_title_substring(window_name)
|
wins = find_windows_by_title_substring(window_name)
|
||||||
|
printLog(f"paste: found {wins} windows matching title substring '{window_name}'")
|
||||||
for hwnd in wins:
|
for hwnd in wins:
|
||||||
if focus_window(hwnd):
|
if focus_window(hwnd):
|
||||||
focused = True
|
focused = True
|
||||||
@@ -199,6 +204,7 @@ class Clipboard:
|
|||||||
# if not found by title, try treating window_name as process name
|
# if not found by title, try treating window_name as process name
|
||||||
if not focused:
|
if not focused:
|
||||||
wins = find_windows_by_process_name(window_name)
|
wins = find_windows_by_process_name(window_name)
|
||||||
|
printLog(f"paste: found {wins} windows matching process name '{window_name}'")
|
||||||
for hwnd in wins:
|
for hwnd in wins:
|
||||||
if focus_window(hwnd):
|
if focus_window(hwnd):
|
||||||
focused = True
|
focused = True
|
||||||
@@ -218,4 +224,4 @@ class Clipboard:
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
clipboard = Clipboard()
|
clipboard = Clipboard()
|
||||||
clipboard.copy("Sample text to copy to clipboard.")
|
clipboard.copy("Sample text to copy to clipboard.")
|
||||||
clipboard.paste(window_name=None, countdown=0)
|
clipboard.paste(window_name=None, countdown=3)
|
||||||
Reference in New Issue
Block a user