Coverage for WinTables.py: 33%

123 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-09-28 16:41 +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 

10 

11from TableWindow import Table_Window 

12 

13app = QApplication(sys.argv) 

14 

15# logging setup 

16log = logging.getLogger("hud") 

17 

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 

25 

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 

38 

39# Global variables 

40b_width = 3 

41tb_height = 29 

42 

43# Class for temporarily storing securities 

44class WindowInfoTemp: 

45 def __init__(self): 

46 self.titles = {} 

47 #print("WindowInfo initialized with an empty dictionary.") 

48 

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 

61 

62 

63class Table(Table_Window): 

64 

65 # In find_table_parameters of WinTables.py 

66 

67 

68 def find_table_parameters(self): 

69 """Find a poker client window with the given table name.""" 

70 window_info = WindowInfoTemp() 

71 

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}") 

78 

79 time_limit = 10 # Limite de temps en secondes 

80 start_time = time.time() # Enregistre l'heure de début 

81 

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 

87 

88 title = window_info.titles[hwnd] 

89 if not title: 

90 continue 

91 

92 if not IsWindowVisible(hwnd): 

93 continue 

94 if GetParent(hwnd) != 0: 

95 continue 

96 

97 HasNoOwner = ctypes.windll.user32.GetWindow(hwnd, GW_OWNER) == 0 

98 WindowStyle = GetWindowLong(hwnd, GWL_EXSTYLE) 

99 

100 if title.split(' ', 1)[0] == "Winamax": 

101 self.search_string = self.search_string.split(' ', 3)[0] 

102 

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 

110 

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}") 

118 

119 if self.number is None: 

120 log.error(f"Window {self.search_string} not found.") 

121 

122 

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 

135 

136 self.b_width = GetSystemMetrics(SM_CXSIZEFRAME) 

137 self.tb_height = GetSystemMetrics(SM_CYCAPTION) 

138 

139 #print(f"Position: ({x}, {y}), Dimensions: {width}x{height}") 

140 #print(f"Border width: {self.b_width}, Title bar height: {self.tb_height}") 

141 

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 

157 

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 

165 

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.") 

174 

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)) 

179 

180 qwindow = (window.windowHandle()) 

181 qwindow.setTransientParent(self.gdkhandle) 

182 qwindow.setFlags(Qt.Tool | Qt.FramelessWindowHint | Qt.WindowDoesNotAcceptFocus | Qt.WindowStaysOnTopHint) 

183 

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)