Создание скрипта для разделения устройств
Tạo vào: 15 tháng 10, 2024
Trả lời bằng O1 Preview bởi Chat01
Tạo vào: 15 tháng 10, 2024
Trả lời bằng O1 Preview bởi Chat01
я пишу скрипт по функционалу подобный программе астер для создания двух рабочих станций из одного системного блока. моя задача разделить фокус на телек с геймпадем и монитор с клавой и мышью, чтобы они не пересекались между собой и не мешали друг другу. я использую винду 11 и 1080 тиай . я составил скелет скрипта, помоги мне реализовать методы в нём. отмечу что помимо мышки клавы и геймпада мне нужно также разделить вывод звука на телек для игр и на пк колонки для монитора.
вот мой код:
"
import win32api
import win32gui
import win32con
import pyHook
import pythoncom
devices = {}
windows = {}
def detect_devices():
# Функция для обнаружения подключенных устройств ввода
pass
def assign_device_to_window(device_id, window_handle):
# Функция для привязки устройства ввода к определенному окну
pass
def on_keyboard_event(event):
# Обработчик событий клавиатуры
# Проверяем, какое устройство сгенерировало событие и перенаправляем его
pass
def on_mouse_event(event):
# Обработчик событий мыши
pass
def main():
# Инициализация устройств и окон
detect_devices()
text# Настройка хуков для перехвата событий ввода hm = pyHook.HookManager() hm.KeyDown = on_keyboard_event hm.MouseAll = on_mouse_event hm.HookKeyboard() hm.HookMouse() # Запуск цикла обработки сообщений pythoncom.PumpMessages()
if name == "main":
main()
"
реализуй сколько сможешь методов и скажи на верном ли я пути.
Вы на правильном пути, но есть некоторые нюансы, которые стоит учесть при реализации вашего скрипта. Основная задача — разделить устройства ввода и аудиовыходы между двумя рабочими станциями на одном ПК. Давайте рассмотрим, как можно реализовать ваши методы.
Функция detect_devices()
должна обнаруживать подключенные устройства ввода и сохранять информацию о них в глобальную переменную devices
. В Windows для этого можно использовать API Raw Input. Ниже приведен пример реализации:
pythonimport win32api import win32gui import win32con import ctypes from ctypes import wintypes def detect_devices(): global devices devices = {} # Получаем список устройств ввода num_devices = ctypes.c_uint() ctypes.windll.user32.GetRawInputDeviceList(None, ctypes.byref(num_devices), ctypes.sizeof(RAWINPUTDEVICELIST)) device_list = (RAWINPUTDEVICELIST * num_devices.value)() ctypes.windll.user32.GetRawInputDeviceList(device_list, ctypes.byref(num_devices), ctypes.sizeof(RAWINPUTDEVICELIST)) for device in device_list: device_handle = device.hDevice device_name_size = ctypes.c_uint() ctypes.windll.user32.GetRawInputDeviceInfoA(device_handle, RIDI_DEVICENAME, None, ctypes.byref(device_name_size)) device_name = ctypes.create_string_buffer(device_name_size.value) ctypes.windll.user32.GetRawInputDeviceInfoA(device_handle, RIDI_DEVICENAME, device_name, ctypes.byref(device_name_size)) # Получаем информацию об устройстве rid_device_info = RID_DEVICE_INFO() rid_device_info.cbSize = ctypes.sizeof(RID_DEVICE_INFO) cbSize = ctypes.c_uint(ctypes.sizeof(RID_DEVICE_INFO)) ctypes.windll.user32.GetRawInputDeviceInfoA(device_handle, RIDI_DEVICEINFO, ctypes.byref(rid_device_info), ctypes.byref(cbSize)) # Сохраняем устройство в словарь devices[device_handle] = { 'name': device_name.value.decode(), 'type': rid_device_info.dwType }
Для этого нам понадобятся некоторые структуры и константы:
python# Константы для Raw Input RIDI_DEVICENAME = 0x20000007 RIDI_DEVICEINFO = 0x2000000b RIM_TYPEMOUSE = 0 RIM_TYPEKEYBOARD = 1 RIM_TYPEHID = 2 class RAWINPUTDEVICELIST(ctypes.Structure): _fields_ = [("hDevice", wintypes.HANDLE), ("dwType", wintypes.DWORD)] class RID_DEVICE_INFO_MOUSE(ctypes.Structure): _fields_ = [("dwId", wintypes.DWORD), ("dwNumberOfButtons", wintypes.DWORD), ("dwSampleRate", wintypes.DWORD), ("fHasHorizontalWheel", wintypes.BOOL)] class RID_DEVICE_INFO_KEYBOARD(ctypes.Structure): _fields_ = [("dwType", wintypes.DWORD), ("dwSubType", wintypes.DWORD), ("dwKeyboardMode", wintypes.DWORD), ("dwNumberOfFunctionKeys", wintypes.DWORD), ("dwNumberOfIndicators", wintypes.DWORD), ("dwNumberOfKeysTotal", wintypes.DWORD)] class RID_DEVICE_INFO_HID(ctypes.Structure): _fields_ = [("dwVendorId", wintypes.DWORD), ("dwProductId", wintypes.DWORD), ("dwVersionNumber", wintypes.DWORD), ("usUsagePage", wintypes.USHORT), ("usUsage", wintypes.USHORT)] class RID_DEVICE_INFO_UNION(ctypes.Union): _fields_ = [("mouse", RID_DEVICE_INFO_MOUSE), ("keyboard", RID_DEVICE_INFO_KEYBOARD), ("hid", RID_DEVICE_INFO_HID)] class RID_DEVICE_INFO(ctypes.Structure): _fields_ = [("cbSize", wintypes.DWORD), ("dwType", wintypes.DWORD), ("info", RID_DEVICE_INFO_UNION)]
Функция assign_device_to_window(device_id, window_handle)
должна сопоставлять идентификатор устройства с определенным окном. Для этого можно создать словарь, который хранит эту информацию:
pythondef assign_device_to_window(device_id, window_handle): global windows windows[device_id] = window_handle
К сожалению, библиотека pyHook
не предоставляет информацию об устройстве, с которого было получено событие. Для получения данных о конкретном устройстве ввода необходимо использовать более низкоуровневые API, такие как Raw Input или DirectInput.
Ниже представлен пример использования API Raw Input для перехвата событий от конкретных устройств:
pythondef register_raw_input_devices(): rid = (RAWINPUTDEVICE * 2)() # Регистрация клавиатуры rid[0].usUsagePage = 0x01 rid[0].usUsage = 0x06 # Клавиатура rid[0].dwFlags = RIDEV_INPUTSINK rid[0].hwndTarget = hwnd # Дескриптор окна # Регистрация мыши rid[1].usUsagePage = 0x01 rid[1].usUsage = 0x02 # Мышь rid[1].dwFlags = RIDEV_INPUTSINK rid[1].hwndTarget = hwnd # Дескриптор окна if not ctypes.windll.user32.RegisterRawInputDevices(rid, 2, ctypes.sizeof(RAWINPUTDEVICE)): print("Ошибка регистрации устройств Raw Input")
Структуры для Raw Input устройств:
pythonclass RAWINPUTDEVICE(ctypes.Structure): _fields_ = [("usUsagePage", wintypes.USHORT), ("usUsage", wintypes.USHORT), ("dwFlags", wintypes.DWORD), ("hwndTarget", wintypes.HWND)] RIDEV_INPUTSINK = 0x00000100
Обработка сообщений Windows для получения событий Raw Input:
pythondef wnd_proc(hwnd, msg, wparam, lparam): if msg == win32con.WM_INPUT: handle_raw_input(lparam) return ctypes.windll.user32.DefWindowProcW(hwnd, msg, wparam, lparam)
Функция для обработки Raw Input событий:
pythondef handle_raw_input(lparam): raw_input_data = RAWINPUT() data_size = ctypes.c_uint(ctypes.sizeof(RAWINPUT)) ctypes.windll.user32.GetRawInputData(lparam, RID_INPUT, ctypes.byref(raw_input_data), ctypes.byref(data_size), ctypes.sizeof(RAWINPUTHEADER)) device_handle = raw_input_data.header.hDevice if device_handle in windows: target_window = windows[device_handle] # Перенаправляем событие в соответствующее окно # Здесь необходимо реализовать логику передачи события
Структуры для Raw Input данных:
pythonclass RAWINPUTHEADER(ctypes.Structure): _fields_ = [("dwType", wintypes.DWORD), ("dwSize", wintypes.DWORD), ("hDevice", wintypes.HANDLE), ("wParam", wintypes.WPARAM)] class RAWMOUSE(ctypes.Structure): _fields_ = [("usFlags", wintypes.USHORT), ("ulButtons", wintypes.ULONG), ("usButtonFlags", wintypes.USHORT), ("usButtonData", wintypes.USHORT), ("ulRawButtons", wintypes.ULONG), ("lLastX", wintypes.LONG), ("lLastY", wintypes.LONG), ("ulExtraInformation", wintypes.ULONG)] class RAWKEYBOARD(ctypes.Structure): _fields_ = [("MakeCode", wintypes.USHORT), ("Flags", wintypes.USHORT), ("Reserved", wintypes.USHORT), ("VKey", wintypes.USHORT), ("Message", wintypes.UINT), ("ExtraInformation", wintypes.ULONG)] class RAWHID(ctypes.Structure): _fields_ = [("dwSizeHid", wintypes.DWORD), ("dwCount", wintypes.DWORD), ("bRawData", ctypes.POINTER(ctypes.c_byte))] class RAWINPUT_UNION(ctypes.Union): _fields_ = [("mouse", RAWMOUSE), ("keyboard", RAWKEYBOARD), ("hid", RAWHID)] class RAWINPUT(ctypes.Structure): _fields_ = [("header", RAWINPUTHEADER), ("data", RAWINPUT_UNION)] RID_INPUT = 0x10000003
Для получения сообщений Windows необходимо создать невидимое окно и запустить цикл обработки сообщений:
pythondef main(): # Инициализация устройств и окон detect_devices() # Создаем невидимое окно wc = win32gui.WNDCLASS() wc.lpszClassName = 'RawInputClass' wc.lpfnWndProc = wnd_proc class_atom = win32gui.RegisterClass(wc) hwnd = win32gui.CreateWindow(wc.lpszClassName, 'Raw Input Window', 0, 0, 0, 0, 0, 0, 0, 0, None) # Регистрируем устройства Raw Input register_raw_input_devices() # Запуск цикла обработки сообщений win32gui.PumpMessages()
Для управления аудиовыходами отдельных приложений можно использовать библиотеку PyCaw, которая предоставляет доступ к Windows Core Audio API.
Пример использования PyCaw для установки устройства вывода для конкретного приложения:
pythonfrom pycaw.pycaw import AudioUtilities, IAudioEndpointVolume def set_application_output(application_name, device_id): sessions = AudioUtilities.GetAllSessions() for session in sessions: if session.Process and session.Process.name() == application_name: volume = session._ctl.QueryInterface(IAudioEndpointVolume) # Здесь необходимо установить устройство вывода для сессии # К сожалению, PyCaw не предоставляет прямого метода для этого
К сожалению, управление устройством вывода на уровне отдельных приложений в Windows не тривиально и может потребовать использования дополнительных библиотек или даже создания виртуальных аудиоустройств.
Вы на правильном пути, но для реализации вашей задачи потребуется использовать более низкоуровневые API и, возможно, написать дополнительные обертки над ними. Вот основные моменты:
Обратите внимание, что работа с Raw Input API и управлением аудиоустройствами может быть сложной и потребует тщательного тестирования. Рекомендуется ознакомиться с официальной документацией Microsoft и примерами использования этих API.