From 58a40b6f9f511cc5e808ab4e2fac2d2cd2aa0013 Mon Sep 17 00:00:00 2001 From: Nitin Kumar Date: Wed, 29 Jan 2025 12:30:03 +0530 Subject: [PATCH] Update to tmux docs, and 2nd POC for windows --- testsuite/Notes.md | 26 ++++++++++--- testsuite/docs/tmux.md | 2 +- testsuite/win_poc.py | 85 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+), 6 deletions(-) create mode 100644 testsuite/win_poc.py diff --git a/testsuite/Notes.md b/testsuite/Notes.md index de7dee7..9b60da4 100644 --- a/testsuite/Notes.md +++ b/testsuite/Notes.md @@ -7,11 +7,27 @@ - Note : You must keep your focus on the terminal for the entire duration of test run. `pyautogui` sends keypress to process on focus. ## Pyautogui alternatives -- POC with pyautogui as a lot of issues, stated above. -- Linux piping +POC with pyautogui as a lot of issues, stated above. + +### Linux / MacOS + - xdotool -- mkfifo + - Seems complicated. It wont be able to manage spf process that well +- mkfifo / Manual linux piping + - Too much manual work to send inputs, even if it works - tmux - - Supports full terminal programs + - Supports full terminal programs and has a python wrapper library + - See `docs/tmux.md` + - Not available for windows +- References + - https://superuser.com/questions/585398/sending-simulated-keystrokes-in-bash + +## Windows + +- Autohotkey +- ControlSend and SendInput utility in windows +- pywin32 library + - Create a new GUI window for test + - Use `win32gui.SendMessage` or `PostMessage` - References - - https://superuser.com/questions/585398/sending-simulated-keystrokes-in-bash \ No newline at end of file + - https://www.reddit.com/r/tmux/comments/l580mi/is_there_a_tmuxlike_equivalent_for_windows/ \ No newline at end of file diff --git a/testsuite/docs/tmux.md b/testsuite/docs/tmux.md index cd0f9f4..5c93110 100644 --- a/testsuite/docs/tmux.md +++ b/testsuite/docs/tmux.md @@ -1,5 +1,5 @@ # Overview -This is to document the behviour of tmux, and how could use it in testsuite +This is to document the behviour of tmux, and how could we use it in testsuite # Tmux concepts and working info - Tmux creates a main server process, and one new process for each session. diff --git a/testsuite/win_poc.py b/testsuite/win_poc.py new file mode 100644 index 0000000..b865069 --- /dev/null +++ b/testsuite/win_poc.py @@ -0,0 +1,85 @@ +import win32gui +import win32con +import win32api +import win32process +import subprocess +import time +from ctypes import * + +class TerminalController: + # Virtual Key codes for special keys + VK_CODES = { + 'ENTER': 0x0D, + 'UP': 0x26, + 'DOWN': 0x28, + 'LEFT': 0x25, + 'RIGHT': 0x27, + 'SPACE': 0x20, + 'TAB': 0x09, + 'ESC': 0x1B + } + + def __init__(self, process_name): + self.process_name = process_name + self.hwnd = None + + def find_window_by_process(self): + def callback(hwnd, pid): + try: + _, process_id = win32process.GetWindowThreadProcessId(hwnd) + if process_id == pid: + self.hwnd = hwnd + return False # Stop enumeration + except: + pass + return True + + # Start the process + process = subprocess.Popen(self.process_name, + creationflags=subprocess.CREATE_NEW_CONSOLE) + time.sleep(1) # Give process time to start + + # Find the window handle + win32gui.EnumWindows(callback, process.pid) + return self.hwnd is not None + + def send_key(self, key): + if not self.hwnd: + raise Exception("Window handle not found") + + if isinstance(key, str): + if key.upper() in self.VK_CODES: + vk_code = self.VK_CODES[key.upper()] + else: + # For regular characters + vk_code = win32api.VkKeyScan(key) & 0xFF + + # Send key down + win32api.PostMessage(self.hwnd, win32con.WM_KEYDOWN, vk_code, 0) + time.sleep(0.05) # Small delay between down and up + # Send key up + win32api.PostMessage(self.hwnd, win32con.WM_KEYUP, vk_code, 0) + + def send_keys(self, keys, delay=0.1): + """Send multiple keys with delay between them""" + for key in keys: + self.send_key(key) + time.sleep(delay) + +# Example usage +def main(): + # Initialize controller with your terminal file manager + controller = TerminalController("superfile") + + if controller.find_window_by_process(): + # Example: Navigate using arrow keys and select with Enter + time.sleep(1) # Wait for application to be ready + + # Send some navigation commands + commands = ['DOWN', 'DOWN', 'ENTER', 'UP', 'RIGHT'] + controller.send_keys(commands) + else: + print("Failed to find terminal window") + +if __name__ == "__main__": + main() \ No newline at end of file