168 lines
5.2 KiB
Python
168 lines
5.2 KiB
Python
|
|
# -*- coding: utf-8 -*-
|
||
|
|
from StreamDock.FeatrueOption import device_type
|
||
|
|
from .StreamDock import StreamDock
|
||
|
|
from ..InputTypes import InputEvent, ButtonKey, EventType
|
||
|
|
from PIL import Image
|
||
|
|
import ctypes
|
||
|
|
import ctypes.util
|
||
|
|
import os, io
|
||
|
|
from ..ImageHelpers.PILHelper import *
|
||
|
|
import random
|
||
|
|
|
||
|
|
|
||
|
|
class StreamDock293s(StreamDock):
|
||
|
|
"""StreamDock293s device class - supports 15 keys and 3 secondary screen keys"""
|
||
|
|
|
||
|
|
KEY_COUNT = 18
|
||
|
|
KEY_MAP = False
|
||
|
|
|
||
|
|
# Image key mapping: logical key -> hardware key (for setting images)
|
||
|
|
_IMAGE_KEY_MAP = {
|
||
|
|
ButtonKey.KEY_1: 13,
|
||
|
|
ButtonKey.KEY_2: 10,
|
||
|
|
ButtonKey.KEY_3: 7,
|
||
|
|
ButtonKey.KEY_4: 4,
|
||
|
|
ButtonKey.KEY_5: 1,
|
||
|
|
ButtonKey.KEY_6: 14,
|
||
|
|
ButtonKey.KEY_7: 11,
|
||
|
|
ButtonKey.KEY_8: 8,
|
||
|
|
ButtonKey.KEY_9: 5,
|
||
|
|
ButtonKey.KEY_10: 2,
|
||
|
|
ButtonKey.KEY_11: 15,
|
||
|
|
ButtonKey.KEY_12: 12,
|
||
|
|
ButtonKey.KEY_13: 9,
|
||
|
|
ButtonKey.KEY_14: 6,
|
||
|
|
ButtonKey.KEY_15: 3,
|
||
|
|
# Secondary screen keys 16-18
|
||
|
|
ButtonKey.KEY_16: 16,
|
||
|
|
ButtonKey.KEY_17: 17,
|
||
|
|
ButtonKey.KEY_18: 18,
|
||
|
|
}
|
||
|
|
|
||
|
|
# Reverse mapping: hardware key -> logical key (for event decoding)
|
||
|
|
_HW_TO_LOGICAL_KEY = {v: k for k, v in _IMAGE_KEY_MAP.items()}
|
||
|
|
|
||
|
|
def __init__(self, transport1, devInfo):
|
||
|
|
super().__init__(transport1, devInfo)
|
||
|
|
|
||
|
|
def get_image_key(self, logical_key: ButtonKey) -> int:
|
||
|
|
"""
|
||
|
|
Convert logical key value to hardware key value (for setting images)
|
||
|
|
|
||
|
|
Args:
|
||
|
|
logical_key: Logical key enum
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
int: Hardware key value
|
||
|
|
"""
|
||
|
|
if logical_key in self._IMAGE_KEY_MAP:
|
||
|
|
return self._IMAGE_KEY_MAP[logical_key]
|
||
|
|
raise ValueError(f"StreamDock293s: Unsupported key {logical_key}")
|
||
|
|
|
||
|
|
def decode_input_event(self, hardware_code: int, state: int) -> InputEvent:
|
||
|
|
"""
|
||
|
|
Decode hardware event codes into a unified InputEvent
|
||
|
|
|
||
|
|
The 293s device supports only regular buttons; hardware code range 1-18
|
||
|
|
"""
|
||
|
|
# Handle state value: 0x02=release, 0x01=press
|
||
|
|
normalized_state = 1 if state == 0x01 else 0
|
||
|
|
|
||
|
|
# Regular button events (1-18)
|
||
|
|
if hardware_code in self._HW_TO_LOGICAL_KEY:
|
||
|
|
return InputEvent(
|
||
|
|
event_type=EventType.BUTTON,
|
||
|
|
key=self._HW_TO_LOGICAL_KEY[hardware_code],
|
||
|
|
state=normalized_state
|
||
|
|
)
|
||
|
|
|
||
|
|
# Unknown event
|
||
|
|
return InputEvent(event_type=EventType.UNKNOWN)
|
||
|
|
|
||
|
|
# Set device screen brightness
|
||
|
|
def set_brightness(self, percent):
|
||
|
|
return self.transport.setBrightness(percent)
|
||
|
|
|
||
|
|
# Set device background image 854 * 480
|
||
|
|
def set_touchscreen_image(self, image):
|
||
|
|
image = Image.open(image)
|
||
|
|
image = to_native_touchscreen_format(self, image)
|
||
|
|
width, height = image.size
|
||
|
|
bgr_data = []
|
||
|
|
|
||
|
|
for x in range(width):
|
||
|
|
for y in range(height):
|
||
|
|
r,g,b = image.getpixel((x,y))
|
||
|
|
bgr_data.extend([b,g,r])
|
||
|
|
arr_type = ctypes.c_char * len(bgr_data)
|
||
|
|
arr_ctypes = arr_type(*bgr_data)
|
||
|
|
|
||
|
|
return self.transport.setBackgroundImg(ctypes.cast(arr_ctypes, ctypes.POINTER(ctypes.c_ubyte)),width * height * 3)
|
||
|
|
|
||
|
|
# Set device key icon image 85 * 85
|
||
|
|
def set_key_image(self, key, path):
|
||
|
|
try:
|
||
|
|
if isinstance(key, int):
|
||
|
|
if key not in range(1, 19):
|
||
|
|
print(f"key '{key}' out of range. you should set (1 ~ 18)")
|
||
|
|
return -1
|
||
|
|
logical_key = ButtonKey(key)
|
||
|
|
else:
|
||
|
|
logical_key = key
|
||
|
|
|
||
|
|
if not os.path.exists(path):
|
||
|
|
print(f"Error: The image file '{path}' does not exist.")
|
||
|
|
return -1
|
||
|
|
|
||
|
|
# Get hardware key value
|
||
|
|
hardware_key = self.get_image_key(logical_key)
|
||
|
|
|
||
|
|
image = Image.open(path)
|
||
|
|
if hardware_key in range(1, 16):
|
||
|
|
# icon
|
||
|
|
rotated_image = to_native_key_format(self, image)
|
||
|
|
elif hardware_key in range(16, 19):
|
||
|
|
# second screen
|
||
|
|
rotated_image = to_native_seondscreen_format(self, image)
|
||
|
|
rotated_image.save("Temporary.jpg", "JPEG", subsampling=0, quality=100)
|
||
|
|
returnvalue = self.transport.setKeyImg(bytes("Temporary.jpg",'utf-8'), hardware_key)
|
||
|
|
os.remove("Temporary.jpg")
|
||
|
|
return returnvalue
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
print(f"Error: {e}")
|
||
|
|
return -1
|
||
|
|
|
||
|
|
def get_serial_number(self):
|
||
|
|
return self.serial_number
|
||
|
|
|
||
|
|
def key_image_format(self):
|
||
|
|
return {
|
||
|
|
'size': (85, 85),
|
||
|
|
'format': "JPEG",
|
||
|
|
'rotation': 90,
|
||
|
|
'flip': (False, False)
|
||
|
|
}
|
||
|
|
|
||
|
|
def secondscreen_image_format(self):
|
||
|
|
return {
|
||
|
|
'size': (80, 80),
|
||
|
|
'format': "JPEG",
|
||
|
|
'rotation': 90,
|
||
|
|
'flip': (False, False)
|
||
|
|
}
|
||
|
|
|
||
|
|
def touchscreen_image_format(self):
|
||
|
|
return {
|
||
|
|
'size': (854, 480),
|
||
|
|
'format': "JPEG",
|
||
|
|
'rotation': 0,
|
||
|
|
'flip': (True, False)
|
||
|
|
}
|
||
|
|
|
||
|
|
# Set device parameters
|
||
|
|
def set_device(self):
|
||
|
|
self.transport.set_report_size(513, 513, 0)
|
||
|
|
self.feature_option.deviceType = device_type.dock_293s
|
||
|
|
pass
|