Coverage for WinTables.py: 34%
121 statements
« prev ^ index » next coverage.py v7.6.3, created at 2024-10-15 19:33 +0000
« prev ^ index » next coverage.py v7.6.3, created at 2024-10-15 19:33 +0000
1import ctypes
2import re
3import logging
4from ctypes import wintypes
5from PyQt5.QtGui import QWindow
6from PyQt5.QtCore import Qt
7from PyQt5.QtWidgets import QApplication
8import sys
9import time
11from TableWindow import Table_Window
13app = QApplication(sys.argv)
15# logging setup
16log = logging.getLogger("hud")
18# Definition of Windows API constants
19GW_OWNER = 4
20GWL_EXSTYLE = -20
21WS_EX_TOOLWINDOW = 0x00000080
22WS_EX_APPWINDOW = 0x00040000
23SM_CXSIZEFRAME = 32
24SM_CYCAPTION = 4
26# Windows functions via ctypes
27EnumWindows = ctypes.windll.user32.EnumWindows
28EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.wintypes.HWND, ctypes.wintypes.LPARAM)
29GetWindowText = ctypes.windll.user32.GetWindowTextW
30GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW
31IsWindowVisible = ctypes.windll.user32.IsWindowVisible
32GetParent = ctypes.windll.user32.GetParent
33GetWindowRect = ctypes.windll.user32.GetWindowRect
34GetWindowLong = ctypes.windll.user32.GetWindowLongW
35GetSystemMetrics = ctypes.windll.user32.GetSystemMetrics
36IsWindow = ctypes.windll.user32.IsWindow
37MoveWindow = ctypes.windll.user32.MoveWindow
39# Global variables
40b_width = 3
41tb_height = 29
44# Class for temporarily storing securities
45class WindowInfoTemp:
46 def __init__(self):
47 self.titles = {}
48 # print("WindowInfo initialized with an empty dictionary.")
51# Function for listing windows and retrieving titles
52def win_enum_handler(hwnd, lParam):
53 # print(f"Handler called for hwnd: {hwnd}")
54 window_info = ctypes.cast(lParam, ctypes.py_object).value
55 length = GetWindowTextLength(hwnd)
56 # print(f"Window text length: {length}")
57 if length > 0:
58 buff = ctypes.create_unicode_buffer(length + 1)
59 GetWindowText(hwnd, buff, length + 1)
60 # print(f"Text retrieved for hwnd {hwnd}: {buff.value}")
61 window_info.titles[hwnd] = buff.value
62 return True
65class Table(Table_Window):
66 # In find_table_parameters of WinTables.py
68 def find_table_parameters(self):
69 """Find a poker client window with the given table name."""
70 window_info = WindowInfoTemp()
72 try:
73 log.debug("before EnumWindows")
74 EnumWindows(EnumWindowsProc(win_enum_handler), ctypes.py_object(window_info))
75 log.debug(f"after EnumWindows found {len(window_info.titles)} windows")
76 except Exception as e:
77 log.error(f"Error during EnumWindows: {e}")
79 time_limit = 10 # Limite de temps en secondes
80 start_time = time.time() # Enregistre l'heure de début
82 for hwnd in window_info.titles:
83 try:
84 if time.time() - start_time > time_limit:
85 log.error(f"Time limit of {time_limit} seconds reached. Exiting loop.")
86 break
88 title = window_info.titles[hwnd]
89 if not title:
90 continue
92 if not IsWindowVisible(hwnd):
93 continue
94 if GetParent(hwnd) != 0:
95 continue
97 # HasNoOwner = ctypes.windll.user32.GetWindow(hwnd, GW_OWNER) == 0
98 # WindowStyle = GetWindowLong(hwnd, GWL_EXSTYLE)
100 if title.split(" ", 1)[0] == "Winamax":
101 self.search_string = self.search_string.split(" ", 3)[0]
103 if re.search(self.search_string, title, re.I):
104 if self.check_bad_words(title):
105 continue
106 self.number = hwnd
107 self.title = title
108 log.debug(f"Found table in hwnd {self.number} title {self.title}")
109 break
111 except IOError as e:
112 if "closed file" in str(e):
113 print(f"Warning: Logging to a closed file for hwnd {hwnd}. Skipping this log entry.")
114 else:
115 log.error(f"IOError for hwnd {hwnd}: {e}")
116 except Exception as e:
117 log.error(f"Unexpected error for hwnd {hwnd}: {e}")
119 if self.number is None:
120 log.error(f"Window {self.search_string} not found.")
122 # In get_geometry of WinTables.py
123 def get_geometry(self):
124 """Get the window geometry."""
125 # print(f"Attempting to retrieve geometry for hwnd: {self.number}")
126 try:
127 rect = wintypes.RECT()
128 if IsWindow(self.number):
129 result = GetWindowRect(self.number, ctypes.byref(rect))
130 if result != 0:
131 x, y = rect.left, rect.top
132 width = rect.right - rect.left
133 height = rect.bottom - rect.top
135 self.b_width = GetSystemMetrics(SM_CXSIZEFRAME)
136 self.tb_height = GetSystemMetrics(SM_CYCAPTION)
138 # print(f"Position: ({x}, {y}), Dimensions: {width}x{height}")
139 # print(f"Border width: {self.b_width}, Title bar height: {self.tb_height}")
141 return {
142 "x": int(x) + self.b_width,
143 "y": int(y) + self.tb_height + self.b_width,
144 "height": int(height) - 2 * self.b_width - self.tb_height,
145 "width": int(width) - 2 * self.b_width,
146 }
147 else:
148 log.error(f"Failed to retrieve GetWindowRect for hwnd: {self.number}")
149 return None
150 else:
151 log.error(f"The window {self.number} is not valid.")
152 return None
153 except Exception as e:
154 log.error(f"Error retrieving geometry: {e}")
155 return None
157 def get_window_title(self):
158 log.debug(f"title for {self.number}")
159 length = GetWindowTextLength(self.number)
160 buff = ctypes.create_unicode_buffer(length + 1)
161 GetWindowText(self.number, buff, length + 1)
162 log.debug(f"title {buff.value}")
163 return buff.value
165 def move_and_resize_window(self, x, y, width, height):
166 """Move and resize the specified window."""
167 if self.number:
168 # print(f"Moving and resizing window {self.number}")
169 MoveWindow(self.number, x, y, width, height, True)
170 # print(f"Window moved to ({x}, {y}) with dimensions {width}x{height}")
171 else:
172 log.info("No window to move.")
174 def topify(self, window):
175 """Make the specified Qt window 'always on top' under Windows."""
176 if self.gdkhandle is None:
177 self.gdkhandle = QWindow.fromWinId(int(self.number))
179 qwindow = window.windowHandle()
180 qwindow.setTransientParent(self.gdkhandle)
181 qwindow.setFlags(Qt.Tool | Qt.FramelessWindowHint | Qt.WindowDoesNotAcceptFocus | Qt.WindowStaysOnTopHint)
183 def check_bad_words(self, title):
184 """Check if the title contains any bad words."""
185 bad_words = ["History for table:", "HUD:", "Chat:", "FPDBHUD", "Lobby"]
186 return any(bad_word in title.lower() for bad_word in bad_words)