Coverage for WinTables.py: 33%
123 statements
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-27 18:50 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2024-09-27 18:50 +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
43# Class for temporarily storing securities
44class WindowInfoTemp:
45 def __init__(self):
46 self.titles = {}
47 #print("WindowInfo initialized with an empty dictionary.")
49# Function for listing windows and retrieving titles
50def win_enum_handler(hwnd, lParam):
51 #print(f"Handler called for hwnd: {hwnd}")
52 window_info = ctypes.cast(lParam, ctypes.py_object).value
53 length = GetWindowTextLength(hwnd)
54 #print(f"Window text length: {length}")
55 if length > 0:
56 buff = ctypes.create_unicode_buffer(length + 1)
57 GetWindowText(hwnd, buff, length + 1)
58 #print(f"Text retrieved for hwnd {hwnd}: {buff.value}")
59 window_info.titles[hwnd] = buff.value
60 return True
63class Table(Table_Window):
65 # 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(f"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.")
123 # In get_geometry of WinTables.py
124 def get_geometry(self):
125 """Get the window geometry."""
126 #print(f"Attempting to retrieve geometry for hwnd: {self.number}")
127 try:
128 rect = wintypes.RECT()
129 if IsWindow(self.number):
130 result = GetWindowRect(self.number, ctypes.byref(rect))
131 if result != 0:
132 x, y = rect.left, rect.top
133 width = rect.right - rect.left
134 height = rect.bottom - rect.top
136 self.b_width = GetSystemMetrics(SM_CXSIZEFRAME)
137 self.tb_height = GetSystemMetrics(SM_CYCAPTION)
139 #print(f"Position: ({x}, {y}), Dimensions: {width}x{height}")
140 #print(f"Border width: {self.b_width}, Title bar height: {self.tb_height}")
142 return {
143 'x': int(x) + self.b_width,
144 'y': int(y) + self.tb_height + self.b_width,
145 'height': int(height) - 2 * self.b_width - self.tb_height,
146 'width': int(width) - 2 * self.b_width
147 }
148 else:
149 log.error(f"Failed to retrieve GetWindowRect for hwnd: {self.number}")
150 return None
151 else:
152 log.error(f"The window {self.number} is not valid.")
153 return None
154 except Exception as e:
155 log.error(f"Error retrieving geometry: {e}")
156 return None
158 def get_window_title(self):
159 log.debug(f"title for {self.number}")
160 length = GetWindowTextLength(self.number)
161 buff = ctypes.create_unicode_buffer(length + 1)
162 GetWindowText(self.number, buff, length + 1)
163 log.debug(f"title {buff.value}")
164 return buff.value
166 def move_and_resize_window(self, x, y, width, height):
167 """Move and resize the specified window."""
168 if self.number:
169 #print(f"Moving and resizing window {self.number}")
170 MoveWindow(self.number, x, y, width, height, True)
171 #print(f"Window moved to ({x}, {y}) with dimensions {width}x{height}")
172 else:
173 log.info("No window to move.")
175 def topify(self, window):
176 """Make the specified Qt window 'always on top' under Windows."""
177 if self.gdkhandle is None:
178 self.gdkhandle = QWindow.fromWinId(int(self.number))
180 qwindow = (window.windowHandle())
181 qwindow.setTransientParent(self.gdkhandle)
182 qwindow.setFlags(Qt.Tool | Qt.FramelessWindowHint | Qt.WindowDoesNotAcceptFocus | Qt.WindowStaysOnTopHint)
184 def check_bad_words(self, title):
185 """Check if the title contains any bad words."""
186 bad_words = ["History for table:", "HUD:", "Chat:", "FPDBHUD", "Lobby"]
187 return any(bad_word in title.lower() for bad_word in bad_words)