forked from Boria138/PortProtonQt
fix: use kernel for detect_gamepad_axes
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
This commit is contained in:
@@ -118,19 +118,25 @@ class InputManager(QObject):
|
|||||||
self.trigger_cooldown = 0.2
|
self.trigger_cooldown = 0.2
|
||||||
|
|
||||||
# Mouse emulation attributes
|
# Mouse emulation attributes
|
||||||
self.mouse_emulation_enabled = True # Enable by default as crutch for external apps
|
self.mouse_emulation_enabled = True
|
||||||
self.ui = None # UInput for virtual mouse
|
self.ui = None
|
||||||
self.stick_x_raw = 0
|
self.stick_x_raw = 0
|
||||||
self.stick_y_raw = 0
|
self.stick_y_raw = 0
|
||||||
self.deadzone = 8000 # Deadzone for sticks
|
|
||||||
self.max_value = 32767 # Max stick value
|
# Параметры осей (будут заполнены из ядра)
|
||||||
self.sensitivity = 8.0 # Cursor sensitivity
|
self.center_x = 127 # центр X оси
|
||||||
|
self.center_y = 127 # центр Y оси
|
||||||
|
self.min_value = 0 # минимум осей
|
||||||
|
self.max_value = 255 # максимум осей
|
||||||
|
self.deadzone_value = 15 # мёртвая зона из ядра (flat параметр)
|
||||||
|
|
||||||
|
self.sensitivity = 8.0
|
||||||
self.scroll_accumulator = 0.0
|
self.scroll_accumulator = 0.0
|
||||||
self.scroll_sensitivity = 0.15 # Scroll sensitivity
|
self.scroll_sensitivity = 0.15
|
||||||
self.scroll_threshold = 0.2 # Scroll threshold
|
self.scroll_threshold = 0.2
|
||||||
self.last_update = time.time()
|
self.last_update = time.time()
|
||||||
self.update_interval = 0.016 # ~60 FPS
|
self.update_interval = 0.016 # ~60 FPS
|
||||||
self.emulation_active = False # Flag for external focus (updated in main thread)
|
self.emulation_active = False
|
||||||
self.emulation_triggered = False
|
self.emulation_triggered = False
|
||||||
self.start_held = False
|
self.start_held = False
|
||||||
self.guide_held = False
|
self.guide_held = False
|
||||||
@@ -1030,15 +1036,27 @@ class InputManager(QObject):
|
|||||||
self.stick_y_raw = 0
|
self.stick_y_raw = 0
|
||||||
self.scroll_accumulator = 0.0
|
self.scroll_accumulator = 0.0
|
||||||
|
|
||||||
|
|
||||||
def handle_scroll(self, raw_value):
|
def handle_scroll(self, raw_value):
|
||||||
"""Обработка прокрутки с правого стика Y"""
|
"""Обработка прокрутки с правого стика Y"""
|
||||||
if not self.mouse_emulation_enabled or not self.emulation_active or not self.ui:
|
if not self.mouse_emulation_enabled or not self.emulation_active or not self.ui:
|
||||||
return
|
return
|
||||||
if abs(raw_value) < self.deadzone:
|
|
||||||
|
# Нормализуем от центра
|
||||||
|
centered_value = raw_value - self.center_y
|
||||||
|
|
||||||
|
if abs(centered_value) < self.deadzone_value:
|
||||||
self.scroll_accumulator = 0.0
|
self.scroll_accumulator = 0.0
|
||||||
return
|
return
|
||||||
normalized = raw_value / self.max_value
|
|
||||||
|
# Нормализуем значение (-1.0 до 1.0)
|
||||||
|
range_val = (self.max_value - self.min_value) / 2
|
||||||
|
normalized = centered_value / range_val
|
||||||
|
|
||||||
|
# Накапливаем прокрутку
|
||||||
self.scroll_accumulator += normalized * self.scroll_sensitivity
|
self.scroll_accumulator += normalized * self.scroll_sensitivity
|
||||||
|
|
||||||
|
# Отправляем события прокрутки
|
||||||
while abs(self.scroll_accumulator) >= self.scroll_threshold:
|
while abs(self.scroll_accumulator) >= self.scroll_threshold:
|
||||||
scroll_step = 1 if self.scroll_accumulator > 0 else -1
|
scroll_step = 1 if self.scroll_accumulator > 0 else -1
|
||||||
self.scroll_wheel(-scroll_step)
|
self.scroll_wheel(-scroll_step)
|
||||||
@@ -1048,18 +1066,35 @@ class InputManager(QObject):
|
|||||||
"""Постоянное обновление позиции мыши на основе состояния стика"""
|
"""Постоянное обновление позиции мыши на основе состояния стика"""
|
||||||
if not self.ui or not self.emulation_active:
|
if not self.ui or not self.emulation_active:
|
||||||
return
|
return
|
||||||
x = self.stick_x_raw
|
|
||||||
y = self.stick_y_raw
|
# Центрируем значения
|
||||||
|
x = self.stick_x_raw - self.center_x
|
||||||
|
y = self.stick_y_raw - self.center_y
|
||||||
|
|
||||||
|
# Применяем мёртвую зону из ядра
|
||||||
magnitude = math.sqrt(x * x + y * y)
|
magnitude = math.sqrt(x * x + y * y)
|
||||||
if magnitude < self.deadzone:
|
|
||||||
|
if magnitude < self.deadzone_value:
|
||||||
return
|
return
|
||||||
norm_x = x / magnitude
|
|
||||||
norm_y = y / magnitude
|
if magnitude > 0:
|
||||||
adjusted_magnitude = max(0.0, min(1.0, (magnitude - self.deadzone) / (self.max_value - self.deadzone)))
|
norm_x = x / magnitude
|
||||||
|
norm_y = y / magnitude
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Нормализуем по диапазону оси
|
||||||
|
max_range = (self.max_value - self.min_value) / 2
|
||||||
|
adjusted_magnitude = (magnitude - self.deadzone_value) / (max_range - self.deadzone_value)
|
||||||
|
adjusted_magnitude = max(0.0, min(1.0, adjusted_magnitude))
|
||||||
|
|
||||||
|
# Нелинейная кривая
|
||||||
adjusted_magnitude = math.pow(adjusted_magnitude, 1.5)
|
adjusted_magnitude = math.pow(adjusted_magnitude, 1.5)
|
||||||
|
|
||||||
speed = adjusted_magnitude * self.sensitivity
|
speed = adjusted_magnitude * self.sensitivity
|
||||||
dx = int(norm_x * speed)
|
dx = int(norm_x * speed)
|
||||||
dy = int(norm_y * speed)
|
dy = int(norm_y * speed)
|
||||||
|
|
||||||
if dx != 0 or dy != 0:
|
if dx != 0 or dy != 0:
|
||||||
self.move_mouse(dx, dy)
|
self.move_mouse(dx, dy)
|
||||||
|
|
||||||
@@ -2170,6 +2205,7 @@ class InputManager(QObject):
|
|||||||
|
|
||||||
if is_joystick == '1':
|
if is_joystick == '1':
|
||||||
logger.info(f"Found gamepad: {device.name}")
|
logger.info(f"Found gamepad: {device.name}")
|
||||||
|
self.detect_gamepad_axes(device)
|
||||||
return device
|
return device
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -2183,6 +2219,34 @@ class InputManager(QObject):
|
|||||||
logger.error(f"Error finding gamepad: {e}", exc_info=True)
|
logger.error(f"Error finding gamepad: {e}", exc_info=True)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def detect_gamepad_axes(self, device: InputDevice) -> None:
|
||||||
|
"""Читаем параметры осей из ядра (диапазон и мёртвую зону)"""
|
||||||
|
try:
|
||||||
|
caps = device.capabilities()
|
||||||
|
if ecodes.EV_ABS not in caps:
|
||||||
|
return
|
||||||
|
|
||||||
|
abs_axes = caps[ecodes.EV_ABS]
|
||||||
|
for code, absinfo in abs_axes:
|
||||||
|
if code == ecodes.ABS_X:
|
||||||
|
self.min_value = absinfo.min
|
||||||
|
self.max_value = absinfo.max
|
||||||
|
self.center_x = (absinfo.min + absinfo.max) // 2
|
||||||
|
self.center_y = (absinfo.min + absinfo.max) // 2
|
||||||
|
self.stick_x_raw = self.center_x
|
||||||
|
self.stick_y_raw = self.center_y
|
||||||
|
|
||||||
|
# Берём мёртвую зону из ядра (flat параметр)
|
||||||
|
self.deadzone_value = absinfo.flat if absinfo.flat > 0 else 15
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"Gamepad axes: min={self.min_value}, max={self.max_value}, "
|
||||||
|
f"center={self.center_x}, deadzone={self.deadzone_value}"
|
||||||
|
)
|
||||||
|
break
|
||||||
|
except Exception as ex:
|
||||||
|
logger.error(f"Error detecting gamepad axes: {ex}")
|
||||||
|
|
||||||
def monitor_gamepad(self) -> None:
|
def monitor_gamepad(self) -> None:
|
||||||
try:
|
try:
|
||||||
while self.running:
|
while self.running:
|
||||||
@@ -2278,8 +2342,8 @@ class InputManager(QObject):
|
|||||||
else:
|
else:
|
||||||
logger.error(f"IOError in gamepad monitoring: {e}")
|
logger.error(f"IOError in gamepad monitoring: {e}")
|
||||||
self.gamepad = None
|
self.gamepad = None
|
||||||
self.stick_x_raw = 0
|
self.stick_x_raw = self.center_x
|
||||||
self.stick_y_raw = 0
|
self.stick_y_raw = self.center_y
|
||||||
self.scroll_accumulator = 0.0
|
self.scroll_accumulator = 0.0
|
||||||
self.start_held = False
|
self.start_held = False
|
||||||
self.guide_held = False
|
self.guide_held = False
|
||||||
|
|||||||
Reference in New Issue
Block a user