import win32gui
import win32con
import threading
import ctypes
import time
from pywinauto.application import Application
from pywinauto import findwindows
from tkinter import Tk, Button, messagebox
# List of rooms and window handles
room_list = []
hwnd_send = None
refresh_interval = 5 # Seconds between each information refresh
# Dictionary to hold information about important components
components_info = {
'RichEdit20W': 'Used for sending and receiving text messages in the chat window.',
'SysHeader32': 'Used to list and manage room members.',
'DlgGroupChat Window Class': 'Main chat room window.',
'Dialog': 'General dialog component used for various interactions.',
'Button': 'Used for executing commands like sending messages or joining rooms.',
'ComboBox': 'Used to select items such as chat rooms or users.',
'Static': 'Displays static text or information.',
'Edit': 'Used for entering text or data.',
'ListBox': 'Displays a list of items such as user lists.',
'TabControl': 'Manages tabs in the user interface.',
'ScrollBar': 'Used for scrolling content in windows.'
}
# Cache for storing scanned components to avoid repeated scanning
components_cache = {}
def init_room_list_cb(hwnd, lparam):
# Callback function to initialize room list
try:
name = win32gui.GetClassName(hwnd)
if name == 'DlgGroupChat Window Class':
global room_list
room_list.append(win32gui.GetWindowText(hwnd))
except Exception as e:
handle_error(e)
def init_room_list():
# Function to initialize the room list
try:
win32gui.EnumWindows(init_room_list_cb, 0)
if not room_list:
print('No rooms found')
except Exception as e:
handle_error(e)
def dlg_group_chat_cb(hwnd, lparam):
# Callback function to get handle for sending messages
try:
name = win32gui.GetClassName(hwnd)
global hwnd_send
if name == 'RichEdit20W':
hwnd_send = hwnd
except Exception as e:
handle_error(e)
def init_room_hwnd(room_name):
# Function to initialize room window handle
try:
window = win32gui.FindWindow('DlgGroupChat Window Class', room_name)
win32gui.EnumChildWindows(window, dlg_group_chat_cb, 0)
except Exception as e:
handle_error(e)
def send_text(text):
# Function to send text message using WinAPI
try:
win32gui.SendMessage(hwnd_send, win32con.WM_SETTEXT, 0, text)
win32gui.SendMessage(hwnd_send, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)
win32gui.SendMessage(hwnd_send, win32con.WM_KEYUP, win32con.VK_RETURN, 0)
except Exception as e:
handle_error(e)
def send_text_with_pywinauto(text):
# Function to send text message using pywinauto
try:
app = Application().connect(title_re=".*" + room_list[0] + ".*")
chat_window = app.window(title_re=".*" + room_list[0] + ".*")
chat_window.set_focus()
chat_window.send_chars(text)
chat_window.send_keystrokes('{ENTER}')
except Exception as e:
handle_error(e)
def read_room_text():
# Function to read text messages from the room
try:
length = win32gui.SendMessage(hwnd_send, win32con.WM_GETTEXTLENGTH, 0, 0)
buffer = ctypes.create_unicode_buffer(length + 1)
win32gui.SendMessage(hwnd_send, win32con.WM_GETTEXT, length + 1, buffer)
room_text = buffer.value
return room_text
except Exception as e:
handle_error(e)
return ""
def count_room_members(window):
# Function to count the number of members in the room
try:
header = win32gui.FindWindowEx(window, None, "SysHeader32", None)
member_count = win32gui.SendMessage(header, win32con.LVM_GETITEMCOUNT)
return member_count
except Exception as e:
handle_error(e)
return 0
def check_member_status(window, index):
# Function to check member status (mic, hand raised, webcam)
try:
header = win32gui.FindWindowEx(window, None, "SysHeader32", None)
item = ctypes.create_string_buffer(256)
list_item = win32gui.LVITEMW()
list_item.iSubItem = 0
list_item.cchTextMax = 256
list_item.pszText = ctypes.cast(item, ctypes.c_wchar_p)
list_item.iImage = -1
win32gui.SendMessage(header, win32con.LVM_GETITEMW, index, ctypes.byref(list_item))
name = list_item.pszText
is_on_mic = list_item.iImage == 10 # Mic status
has_hand_raised = list_item.iImage == 11 # Hand raised status
is_on_cam = list_item.iImage == 12 # Webcam status
return name, is_on_mic, has_hand_raised, is_on_cam
except Exception as e:
handle_error(e)
return "", False, False, False
def get_component_info():
# Function to get information about important Paltalk components
try:
components = []
new_components = []
def enum_windows_callback(hwnd, lparam):
try:
class_name = win32gui.GetClassName(hwnd)
if class_name not in components_info:
new_components.append((class_name, 'Unknown component'))
components_info[class_name] = 'Unknown component'
components.append((class_name, components_info.get(class_name, 'Unknown component')))
except Exception as e:
handle_error(e)
return True
# Check cache first
if not components_cache:
win32gui.EnumWindows(enum_windows_callback, None)
components_cache['components'] = components # Cache the results
if new_components:
print("New components detected:")
for comp, desc in new_components:
print(f"{comp}: {desc}")
# Update the description of the newly detected component
components_info[comp] = f"This component ({comp}) is newly detected and its function is currently unknown."
else:
components = components_cache['components']
return components
except Exception as e:
handle_error(e)
return []
def refresh_room_info():
# Function to refresh room information periodically
while True:
try:
window = win32gui.FindWindow("DlgGroupChat Window Class", room_list[0])
member_count = count_room_members(window)
print("Number of Members:", member_count)
for i in range(member_count):
name, is_on_mic, has_hand_raised, is_on_cam = check_member_status(window, i)
print(f"Member: {name}, On Mic: {is_on_mic}, Hand Raised: {has_hand_raised}, On Cam: {is_on_cam}")
time.sleep(refresh_interval)
except Exception as e:
handle_error(e)
def create_scan_button():
# Function to create a scan button for manual scanning
def scan_components():
components = get_component_info()
print("Component Information:")
for comp, info in components:
print(f"{comp}: {info}")
root = Tk()
root.title("Component Scanner")
scan_button = Button(root, text="Scan Components", command=scan_components)
scan_button.pack(pady=20)
root.mainloop()
def handle_error(e):
# Function to handle errors and provide suggestions
error_message = str(e)
suggestions = {
'init_room_list': 'Make sure the Paltalk application is running and there are active chat rooms.',
'send_text': 'Ensure the RichEdit20W component is correctly initialized and accessible.',
'read_room_text': 'Check if the RichEdit20W component is available and contains text.',
'count_room_members': 'Ensure the SysHeader32 component is available and accessible.',
'check_member_status': 'Make sure the member index is valid and the SysHeader32 component is accessible.'
}
for key in suggestions:
if key in error_message:
print(f"Error in {key}: {suggestions[key]}")
messagebox.showerror("Error", f"Error in {key}: {suggestions[key]}")
return
print(f"Error: {error_message}")
messagebox.showerror("Error", f"Error: {error_message}")
if __name__ == '__main__':
try:
init_room_list()
print('Rooms:', room_list)
if room_list:
room_name = room_list[0] # Get the first room name
init_room_hwnd(room_name)
send_text_with_pywinauto(f'✔ Connected to the room: {room_name}')
room_text = read_room_text()
print("Room Text:", room_text)
refresh_thread = threading.Thread(target=refresh_room_info)
refresh_thread.start()
# Start component scanner UI
scan_thread = threading.Thread(target=create_scan_button)
scan_thread.start()
else:
print("No rooms found")
except Exception as e:
handle_error(e)
### Main Functions of the Bot:
1. **Connect to Paltalk Room**:
- The bot can scan the list of existing chat rooms and connect to the first room in the list.
2. **Detect and List Room Windows**:
- The bot uses `win32gui.EnumWindows` to scan and list the windows of existing chat rooms.
3. **Handle Room Names with Special Characters or Emoji**:
- The bot can handle room names that contain special characters or emojis and print the room name when connected.
4. **Send and Receive Unicode Messages**:
- The bot can send and receive Unicode messages, ensuring no errors when handling special characters.
5. **Count Number of Members in the Room**:
- The bot can count the number of members in the chat room and display this information.
6. **Count Number of Raised Hands**:
- The bot can count the number of members who have raised their hands in the chat room.
7. **Check Member Webcam Status**:
- The bot can determine who has their webcam on and display the number of active webcams.
8. **Check Member Microphone Status**:
- The bot can determine who is holding the microphone and display this information.
9. **Refresh Member Information Periodically**:
- The bot can refresh information about the number of members and their status periodically to ensure information is always up-to-date.
10. **Create Manual Scan Button**:
- The bot has a simple interface with a button that, when pressed, will scan and list the current user interface components.
11. **Detect, List, and Describe New UI Components**:
- When pressing the user interface scan button, the bot will detect and list new UI components, describe their functions, and then save the list of new components to memory.
12. **Error Notification and Suggestion for Fixes**:
- When the bot encounters an error, it will display an error message and provide suggestions for the user on how to fix the error.
### Detailed Description of Key Functions:
1. **Connect to Paltalk Room**:
- The bot scans and connects to the first chat room it finds.
- Example: Connect to `Room A` and display the message "✔ Connected to the room: Room A".
2. **Detect and List Room Windows**:
- The bot uses `win32gui.EnumWindows` to list the room windows.
- Example: "Rooms: ['Room A', 'Room B']".
3. **Handle Room Names with Special Characters or Emoji**:
- The bot can handle room names like "🚀 Space Room 🌌" and display the correct name when connected.
4. **Send and Receive Unicode Messages**:
- The bot uses `win32gui.SendMessage` and `pywinauto` to send Unicode messages.
- Example: "Hello, 🌍!" sent and received without errors.
5. **Count Number of Members in the Room**:
- The bot uses `SysHeader32` to count and display the number of members.
- Example: "Number of Members: 15".
6. **Count Number of Raised Hands**:
- The bot checks member statuses and counts the number of raised hands.
- Example: "Number of Hands Raised: 3".
7. **Check Member Webcam Status**:
- The bot checks the webcam status of members.
- Example: "Number of Webcams On: 2".
8. **Check Member Microphone Status**:
- The bot checks the microphone status of members.
- Example: "Member: John, On Mic: True".
9. **Refresh Member Information Periodically**:
- The bot uses `threading.Thread` to refresh information about the number of members and their statuses periodically.
- Example: Update every 5 seconds.
10. **Create Manual Scan Button**:
- The bot uses Tkinter to create a simple interface with a manual scan button.
- Example: When pressing the "Scan Components" button, the bot will scan and list new components.
11. **Detect, List, and Describe New UI Components**:
- When pressing the scan button, the bot detects and lists new UI components, describing their functions.
- Example: "New components detected: NewComponent1: This component (NewComponent1) is newly detected and its function is currently unknown."
12. **Error Notification and Suggestion for Fixes**:
- When encountering an error, the bot displays an error message and suggests fixes.
- Example: "Error in send_text: Ensure the RichEdit20W component is correctly initialized and accessible."
Vào lúc 13:33:47 UTC+7 ngày Thứ Tư, 22 tháng 1, 2025, Hakan Canyakan đã viết: