Notice: This forum has been recovered from an old backup, so some content, links, and dates may be outdated. The forum is currently read-only while we restore sign-in and registration functionality. Details

If you find this forum valuable and would like to help keep it online, donations to help cover hosting and domain costs are greatly appreciated, but never expected. You can support the forum through Buy Me a Coffee or Ko-fi. Thank you for helping preserve the EventGhost community.

HID PlugIn

Allgemeines zum Thema EventGhost
User avatar
Bitmonster
Site Admin
Posts: 2239
Joined: Mon Feb 06, 2006 10:28 pm

Post by Bitmonster »

Wahrscheinlich weil ich es bisher nicht gebraucht habe und daher schlichtweg vergessen habe. Kannst du einfach in RawReceiverPlugin.py reinpatchen:
def TriggerEvent(self, eventString, payload=None):
...
PluginClass.TriggerEnduringEvent(self, newEventString, payload)

Kommt dann auch in der nächsten Beta.
Bartman
Plugin Developer
Posts: 881
Joined: Sun Feb 12, 2006 9:03 am

Post by Bartman »

wenn ich eine zweite Instanz hinzuf├╝ge, dann taucht der event ja unter HID2.event im Log auf.
Das w├╝rde bedeuten, dass die Reihenfolge ├╝ber das Prefix entscheidet. Ein Prefix wird ja auch derzeit nicht unterst├╝tzt.

edit
Außerdem stolpere ich gelegentlich über folgenden Fehler.
Wirklich reproduzieren kann ich ihn nicht, aber wenn er einmal auftritt, dann passiert es bei jedem Klick im Konfigurationsbaum.

Code: Select all

19:59:54 Traceback (most recent call last):
19:59:54   File "D:\Media\EventGhost\eg\MainFrame.py", line 344, in OnTreeSetFocus
19:59:54     self.focusEvent.Fire("Tree")
19:59:54   File "D:\Media\EventGhost\eg\Utils.py", line 34, in Fire
19:59:54     handler(*args, **kwargs)
19:59:54   File "D:\Media\EventGhost\eg\MainFrame.py", line 621, in OnFocusChange
19:59:54     canCut, canCopy, canPaste, canDelete = self.GetEditCmdState(focus)
19:59:54   File "D:\Media\EventGhost\eg\MainFrame.py", line 637, in GetEditCmdState
19:59:54     selection.CanPaste(), 
19:59:54   File "D:\Media\EventGhost\eg\TreeItems\TreeItem.py", line 294, in CanPaste
19:59:54     if self.DropTest(EventItem):
19:59:54 NameError: global name 'EventItem' is not defined
User avatar
Bitmonster
Site Admin
Posts: 2239
Joined: Mon Feb 06, 2006 10:28 pm

Post by Bitmonster »

Der Prefix ist nicht dokumentiert, aber du kannst ihn trotzdem selber ändern über:
self.info.eventPrefix = WasAuchImmer
in der __start__ Methode.
User avatar
Bitmonster
Site Admin
Posts: 2239
Joined: Mon Feb 06, 2006 10:28 pm

Post by Bitmonster »

Ok, 885 ist oben und der andere NameError sollte auch gefixt sein. Die Version ist aber nicht so sonderlich gepr├╝ft. Zumindest eines ist kein Bug sondern Absicht:
Einige Bezeichnungen der Tasten des Keyboard-Plugins haben sich ge├ñndert. Dieses war notwendig, damit die vom Plugin kommenden Bezeichnungen direkt in SendKeys verwendet werden k├Ânnen. Betrifft haupts├ñchlich die Media-Tasten und die OEM-Tasten. Also wirst du wohl manche Hotkeys neu anlernen m├╝ssen.
Bartman
Plugin Developer
Posts: 881
Joined: Sun Feb 12, 2006 9:03 am

Post by Bartman »

Hier mal die deutlich aufgebohrte Fassung des PlugIns.
Mir fehlen nur noch ordentliche Namen f├╝r die Buttons und die Values.
Die init.py kann dann auch weg. Die alte Fassung ist dann auch nicht mehr kompatibel.

Code: Select all

import eg

class PluginInfo(eg.PluginInfo):
    name = "HID"
    author = "Bartman"
    version = "1.0.0"
    description = "Communication with HID devices."

import time
import binascii
import ctypes
import _winreg
import sys
import threading
import win32con
import win32event
import win32file
import wx
import wx.lib.mixins.listctrl as listmix

from ctypes import Structure, Union, c_byte, c_char, c_int, c_long, c_ulong, c_ushort, c_wchar
from ctypes import pointer, byref, sizeof, POINTER
from ctypes.wintypes import ULONG, BOOLEAN

class Text:
    manufacturer = "Manufacturer"
    deviceName = "Device Name"
    connected = "Connected"
    eventName = "Event prefix (optional):"
    yes = "Yes"
    no = "No"
    enduringEvents = "Trigger enduring events for buttons"
    rawDataEvents = "Use raw Data as event name"
    noOtherPort = "Use selected device only if connected to current port"
    errorFind = "Error finding HID device: "
    errorOpen = "Error opening HID device: "
    errorRead = "Error reading HID device: "
    errorRetrieval = "Error getting HID device info."
    errorMultipleDevices = "Multiple devices found. Don't know which to use."
    errorInvalidDataIndex = "Found data index not defined as button or control value."

#structures for ctypes
class GUID(Structure):
    _fields_ = [
        ("Data1", c_ulong),
        ("Data2", c_ushort),
        ("Data3", c_ushort),
        ("Data4", c_byte * 8)
    ]

class SP_DEVICE_INTERFACE_DATA(Structure):
    _fields_ = [("cbSize", c_ulong),
        ("InterfaceClassGuid", GUID),
        ("Flags", c_ulong),
        ("Reserved", POINTER(ULONG))
    ]
   
class SP_DEVICE_INTERFACE_DETAIL_DATA_A(Structure):
    _fields_ = [("cbSize", c_ulong),
        ("DevicePath", c_char * 255)
    ]

class HIDD_ATTRIBUTES(Structure):
    _fields_ = [("cbSize", c_ulong),
        ("VendorID", c_ushort),
        ("ProductID", c_ushort),
        ("VersionNumber", c_ushort)
    ]

class HIDP_CAPS(Structure):
    _fields_ = [
        ("Usage", c_ushort),
        ("UsagePage", c_ushort),
        ("InputReportByteLength", c_ushort),
        ("OutputReportByteLength", c_ushort),
        ("FeatureReportByteLength", c_ushort),
        ("Reserved", c_ushort * 17),
        ("NumberLinkCollectionNodes", c_ushort),
        ("NumberInputButtonCaps", c_ushort),
        ("NumberInputValueCaps", c_ushort),
        ("NumberInputDataIndices", c_ushort),
        ("NumberOutputButtonCaps", c_ushort),
        ("NumberOutputValueCaps", c_ushort),
        ("NumberOutputDataIndices", c_ushort),
        ("NumberFeatureButtonCaps", c_ushort),
        ("NumberFeatureValueCaps", c_ushort),
        ("NumberFeatureDataIndices", c_ushort)
    ]
   
class HIDP_CAPS_UNION(Union):
    class HIDP_BUTTON_CAPS_RANGE(Structure):
        _fields_ = [
            ("UsageMin", c_ushort),
            ("UsageMax", c_ushort),
            ("StringMin", c_ushort),
            ("StringMax", c_ushort),
            ("DesignatorMin", c_ushort),
            ("DesignatorMax", c_ushort),
            ("DataIndexMin", c_ushort),
            ("DataIndexMax", c_ushort)
        ]
   
    class HIDP_BUTTON_CAPS_NOT_RANGE(Structure):
        _fields_ = [
            ("Usage", c_ushort),
            ("Reserved1", c_ushort),
            ("StringIndex", c_ushort),
            ("Reserved2", c_ushort),
            ("DesignatorIndex", c_ushort),
            ("Reserved3", c_ushort),
            ("DataIndex", c_ushort),
            ("Reserved4", c_ushort)
        ]

    _fields_ = [
        ("Range", HIDP_BUTTON_CAPS_RANGE),
        ("NotRange", HIDP_BUTTON_CAPS_NOT_RANGE)
    ]

class HIDP_BUTTON_CAPS(Structure):
    _fields_ = [
        ("UsagePage", c_ushort),
        ("ReportID", c_char),
        ("IsAlias", BOOLEAN),
        ("BitField", c_ushort),
        ("LinkCollection", c_ushort),
        ("LinkUsage", c_ushort),
        ("LinkUsagePage", c_ushort),
        ("IsRange", BOOLEAN),
        ("IsStringRange", BOOLEAN),
        ("IsDesignatorRange", BOOLEAN),
        ("IsAbsolute", BOOLEAN),
        ("Reserved", c_ulong * 10),
        ("Info", HIDP_CAPS_UNION)
    ]

class HIDP_VALUE_CAPS(Structure):
    _fields_ = [
        ("UsagePage", c_ushort),
        ("ReportID", c_char),
        ("IsAlias", BOOLEAN),
        ("BitField", c_ushort),
        ("LinkCollection", c_ushort),
        ("LinkUsage", c_ushort),
        ("LinkUsagePage", c_ushort),
        ("IsRange", BOOLEAN),
        ("IsStringRange", BOOLEAN),
        ("IsDesignatorRange", BOOLEAN),
        ("IsAbsolute", BOOLEAN),
        ("HasNull", BOOLEAN),
        ("Reserved", c_char),
        ("BitSize", c_ushort),
        ("ReportCount", c_ushort),
        ("Reserved2", c_ushort * 5),
        ("UnitsExp", c_ulong),
        ("Units", c_ulong),
        ("LogicalMin", c_long),
        ("LogicalMax", c_long),
        ("PhysicalMin", c_long),
        ("PhysicalMax", c_long),
        ("Info", HIDP_CAPS_UNION)
    ]

class HIDP_DATA(Structure):
    class HIDP_DATA_VALUE(Union):
        _fields_ = [
            ("RawValue", c_ulong),
            ("On", BOOLEAN),
        ]

    _fields_ = [
        ("DataIndex", c_ushort),
        ("Reserved", c_ushort),
        ("Data", HIDP_DATA_VALUE)
    ]

# Flags controlling what is included in the device information set built
# by SetupDiGetClassDevs
DIGCF_DEFAULT         = 0x00000001  # only valid with DIGCF_DEVICEINTERFACE
DIGCF_PRESENT         = 0x00000002
DIGCF_ALLCLASSES      = 0x00000004
DIGCF_PROFILE         = 0x00000008
DIGCF_DEVICEINTERFACE = 0x00000010

#constants to identify the device info
DEVICE_PATH = 0
VENDOR_ID = 1
VENDOR_STRING = 2
PRODUCT_ID = 3
PRODUCT_STRING = 4
VERSION_NUMBER = MAX_INDEX = 5


#helper class to iterate, find and open hid devices
class HIDHelper:
    text = Text
    deviceList = []
   
    def __init__(self):
        self.UpdateDeviceList()

    def UpdateDeviceList(self):
        self.deviceList = []
       
        #dll references
        setupapiDLL = ctypes.windll.setupapi
        hidDLL =  ctypes.windll.hid
       
        #prepare Interfacedata
        interfaceInfo = SP_DEVICE_INTERFACE_DATA()
        interfaceInfo.cbSize = sizeof(interfaceInfo)
       
        #prepare InterfaceDetailData Structure
        interfaceDetailData = SP_DEVICE_INTERFACE_DETAIL_DATA_A()
        interfaceDetailData.cbSize = 5
       
        #prepare HIDD_ATTRIBUTES
        hiddAttributes = HIDD_ATTRIBUTES()
        hiddAttributes.cbSize = sizeof(hiddAttributes)
       
        #get guid for HID device class
        g = GUID()
        hidDLL.HidD_GetHidGuid(byref(g))
       
        #get handle to the device information set
        hinfo = setupapiDLL.SetupDiGetClassDevsA(byref(g), None, None,
            DIGCF_PRESENT + DIGCF_DEVICEINTERFACE)
       
        #enumerate devices
        i = 0
        while setupapiDLL.SetupDiEnumDeviceInterfaces(hinfo,
            None, byref(g), i, byref(interfaceInfo)):
            device = {}
            i += 1
       
            #get the required size
            requiredSize = c_ulong()
            setupapiDLL.SetupDiGetDeviceInterfaceDetailA(hinfo,
                byref(interfaceInfo), None, 0, byref(requiredSize), None)
            if requiredSize.value > 250:
                eg.PrintError(self.text.errorRetrieval)
                continue #prevent a buffer overflow

            #get the actual info
            setupapiDLL.SetupDiGetDeviceInterfaceDetailA(
                hinfo,
                byref(interfaceInfo),
                byref(interfaceDetailData),
                requiredSize,
                pointer(requiredSize),
                None
            )
            device[DEVICE_PATH] = interfaceDetailData.DevicePath

            #get handle to HID device
            try:
                hidHandle = win32file.CreateFile(
                    device[DEVICE_PATH],
                    win32con.GENERIC_READ, #|win32con.GENERIC_WRITE,
                    win32con.FILE_SHARE_READ|win32con.FILE_SHARE_WRITE,
                    None,
                    win32con.OPEN_EXISTING,
                    0,
                    0
                )
                #skipping devices which cannot be opened
                #(e.g. mice & keyboards, which are opened exclusivly by OS)
                if int(hidHandle) <= 0:
                    continue
            except:
                continue
               
            #getting additional info
            hidDLL.HidD_GetAttributes(int(hidHandle), byref(hiddAttributes))
            device[VENDOR_ID] = hiddAttributes.VendorID
            device[PRODUCT_ID] = hiddAttributes.ProductID
            device[VERSION_NUMBER] = hiddAttributes.VersionNumber
           
            #prepare string buffer for device info strings
            hidpStringType = c_wchar * 128
            infoStr = hidpStringType()
           
            #getting manufacturer
            result = hidDLL.HidD_GetManufacturerString(
                int(hidHandle), byref(infoStr), ctypes.sizeof(infoStr))
            if not result:
                #close handle
                win32file.CloseHandle(hidHandle)
                eg.PrintError(self.text.errorRetrieval)
                continue
            device[VENDOR_STRING] = infoStr.value
               
            #getting device name
            result = hidDLL.HidD_GetProductString(
                int(hidHandle), byref(infoStr), ctypes.sizeof(infoStr))
            if not result:
                #close handle
                win32file.CloseHandle(hidHandle)
                eg.PrintError(self.text.errorRetrieval)
                continue
            device[PRODUCT_STRING] = infoStr.value

            #close handle
            win32file.CloseHandle(hidHandle)
           
            #add device to internal list
            self.deviceList.append(device)

        #end loop
        #destroy deviceinfolist
        setupapiDLL.SetupDiDestroyDeviceInfoList(hinfo)
           

    #gets the devicePath
    #the devicePath parameter is only used with multiple same devices
    def GetDevicePath(self,
        noOtherPort,
        devicePath,
        vendorID,
        productID,
        versionNumber
    ):
        found = 0
        path = ""
        for item in self.deviceList:
            if noOtherPort:
                #just search for devicepath
                if item[DEVICE_PATH] == devicePath:
                    #found right device
                    return devicePath
            else:
                #find the right vendor and product ids
                if item[VENDOR_ID] == vendorID \
                    and item[PRODUCT_ID] == productID \
                    and item[VERSION_NUMBER] == versionNumber:
                    found = found + 1
                    if item[DEVICE_PATH] == devicePath:
                        #found right device
                        return devicePath
                    path = item[DEVICE_PATH]
       
        if found == 1:
            return path
       
        #multiple devices found
        #don't know which to use
        if found > 1:
            eg.PrintError(self.text.errorMultipleDevices)

        return None


class HIDThread(threading.Thread):
    def __init__(self,
        plugin,
        helper,
        enduringEvents,
        rawDataEvents,
        noOtherPort,
        devicePath,
        vendorID,
        vendorString,
        productID,
        productString,
        versionNumber
    ):
        self.text = Text
        self.deviceName = vendorString + " " + productString
        self.abort = False
        self._overlappedRead = win32file.OVERLAPPED()
        self._overlappedRead.hEvent = win32event.CreateEvent(None, 1, 0, None)
       
        #getting devicePath
        self.devicePath = helper.GetDevicePath(
            noOtherPort,
            devicePath,
            vendorID,
            productID,
            versionNumber
        )
       
        if not self.devicePath:
            eg.PrintError(self.text.errorFind + self.deviceName)
            return
       
        threading.Thread.__init__(self, name = self.devicePath)
       
        #setting members
        self.plugin = plugin
        self.helper = helper
        self.enduringEvents = enduringEvents
        self.rawDataEvents = rawDataEvents
        self.start()
   

    def AbortThread(self):
        self.abort = True
        win32event.SetEvent(self._overlappedRead.hEvent)
   
   
    def run(self):
        #open file/devcice
        try:
            handle = win32file.CreateFile(
                self.devicePath,
                    win32con.GENERIC_READ, #|win32con.GENERIC_WRITE,
                    win32con.FILE_SHARE_READ, #| win32con.FILE_SHARE_WRITE,
                None, # no security
                win32con.OPEN_EXISTING,
                win32con.FILE_ATTRIBUTE_NORMAL | win32con.FILE_FLAG_OVERLAPPED,
                0
            )
        except:
            eg.PrintError(self.text.errorOpen + self.deviceName)
            return
       
        #getting data to get the right buffer size
        hidDLL =  ctypes.windll.hid
        setupapiDLL = ctypes.windll.setupapi
       
        #get preparsed data
        preparsedData = c_ulong()
        result = hidDLL.HidD_GetPreparsedData(
            int(handle),
            ctypes.byref(preparsedData)
        )
       
        #getCaps
        hidpCaps = HIDP_CAPS()
        result = hidDLL.HidP_GetCaps(preparsedData, ctypes.byref(hidpCaps))

        n = hidpCaps.InputReportByteLength
        rt = c_int(0)   #report type input
        rl = c_ulong(n)  #report length
        maxDataL = hidDLL.HidP_MaxDataListLength(rt, preparsedData)
       
        #getting button caps
        bCapsArrL = c_ushort(hidpCaps.NumberInputButtonCaps)
        bCapsArrType = HIDP_BUTTON_CAPS * bCapsArrL.value
        bCapsArr = bCapsArrType()
       
        hidDLL.HidP_GetButtonCaps(
            rt,
            ctypes.byref(bCapsArr),
            ctypes.byref(bCapsArrL),
            preparsedData
        )
       
        #getting value caps
        vCapsArrL = c_ushort(hidpCaps.NumberInputValueCaps)
        vCapsArrType = HIDP_VALUE_CAPS * vCapsArrL.value
        vCapsArr = vCapsArrType()
       
        hidDLL.HidP_GetValueCaps(
            rt,
            ctypes.byref(vCapsArr),
            ctypes.byref(vCapsArrL),
            preparsedData
        )

        #parsing caps
        # prepare a list to find and store for each index
        # whether it is a button or value
        oldValues = {}
        dataIndexType = [0] * hidpCaps.NumberInputDataIndices

        #list entries depending on caps
        for i in range(bCapsArrL.value):
            if bCapsArr[i].IsRange:
                for ii in range(
                    bCapsArr[i].Info.Range.DataIndexMin,
                    bCapsArr[i].Info.Range.DataIndexMax + 1
                ):
                    dataIndexType[ii] = 1
            else:
                ii = bCapsArr[i].Info.NotRange.DataIndex
                dataIndexType[ii] = 1


        for i in range(vCapsArrL.value):
            if vCapsArr[i].IsRange:
                for ii in range(
                    vCapsArr[i].Info.Range.DataIndexMin,
                    vCapsArr[i].Info.Range.DataIndexMax + 1
                ):
                    dataIndexType[ii] = 2
                    oldValues[ii] = sys.maxint
            else:
                ii = vCapsArr[i].Info.NotRange.DataIndex
                dataIndexType[ii] = 2
                oldValues[ii] = sys.maxint
       
        #prepare data array with maximum possible length
        DataArrayType = HIDP_DATA * maxDataL
        data = DataArrayType()
       
        while not self.abort:
            #try to read and wait for an event to happen           
            try:
                win32event.ResetEvent(self._overlappedRead.hEvent)
                rc, buf = win32file.ReadFile(handle, n, self._overlappedRead)
                #waiting for an event
                win32event.WaitForSingleObject(
                    self._overlappedRead.hEvent,
                    win32event.INFINITE
                )
            except:
                eg.PrintError(self.text.errorRead + self.deviceName)
                self.abort = True

            #parse data
            if len(buf) == n and not self.abort:
                #raw data events
                if maxDataL == 0 or self.rawDataEvents:
                    read = str(buf)
                    self.plugin.TriggerEvent(
                        binascii.hexlify(read).upper()
                    )
                else:
                    dataL = c_ulong(maxDataL)
                    result = hidDLL.HidP_GetData(
                        rt,
                        ctypes.byref(data),
                        ctypes.byref(dataL),
                        preparsedData,
                        ctypes.c_char_p(str(buf)),
                        rl
                    )
                    #parse data to trigger events
                    btnPressed = []
                    for i in range(dataL.value):
                        tmpIndex = data[i].DataIndex
                        if dataIndexType[tmpIndex] == 1:#button
                            #collect buttons pressed
                            btnPressed.append(str(tmpIndex))
                        elif dataIndexType[tmpIndex] == 2:#control value
                            newValue = int(data[i].Data.RawValue)
                            if newValue == oldValues[tmpIndex]:
                                continue
                            oldValues[tmpIndex] = newValue
                            self.plugin.TriggerEvent(
                                "Value." + str(tmpIndex),
                                payload = newValue
                            )
                        else:
                            eg.PrintError(self.text.errorInvalidDataIndex)
                    if len(btnPressed):
                        #one or more buttons pressed
                        #btnPressed.sort()
                        evtName = "Button." + "+".join(btnPressed)
                        if self.enduringEvents:
                            self.plugin.TriggerEnduringEvent(evtName)
                        else:
                            self.plugin.TriggerEvent(evtName)
                    elif self.enduringEvents:
                        #no buttons pressed anymore
                        self.plugin.EndLastEvent()
                    else:
                        #trigger event so that releasing all buttons
                        #can get noticed even w/o enduring events
                        self.plugin.TriggerEvent("Button.None")

        #loop aborted
        if self.enduringEvents:
            self.plugin.EndLastEvent()
       
        win32file.CloseHandle(handle)

        #free references
        hidDLL.HidD_FreePreparsedData(ctypes.byref(preparsedData))

        #HID thread finished


class HID(eg.PluginClass):
    helper = None
    canMultiLoad = True
    text = Text
    thread = None
   
    def GetLabel(self,
        eventName,
        enduringEvents,
        rawDataEvents,
        noOtherPort,
        devicePath,
        vendorID,
        vendorString,
        productID,
        productString,
        versionNumber
    ):
        prefix = "HID:"
        if not vendorString or not productString:
            return prefix
        if productString.find(vendorString) != -1:
            #productString already contains manufacturer
            return prefix + " " + productString
        return prefix + " " + vendorString + " " + productString
   

    def __start__(self,
        eventName,
        enduringEvents,
        rawDataEvents,
        noOtherPort,
        devicePath,
        vendorID,
        vendorString,
        productID,
        productString,
        versionNumber
    ):
        if eventName:
            self.info.eventPrefix = eventName
        else:
            self.info.eventPrefix = "HID"
        #ensure helper object is up to date
        if not self.helper:
            self.helper = HIDHelper()
        else:
            self.helper.UpdateDeviceList()

        #create thread
        self.thread = HIDThread(
            self,
            self.helper,
            enduringEvents,
            rawDataEvents,
            noOtherPort,
            devicePath,
            vendorID,
            vendorString,
            productID,
            productString,
            versionNumber
        )

    def __stop__(self):
        self.thread.AbortThread()
               
           
    def Configure(self,
        eventName = "",
        enduringEvents = True,
        rawDataEvents = False,
        noOtherPort = False,
        devicePath = None,
        vendorID = None,
        vendorString = None,
        productID = None,
        productString = None,
        versionNumber = None
    ):
        #ensure helper object is up to date
        if not self.helper:
            self.helper = HIDHelper()
        else:
            self.helper.UpdateDeviceList()

        dialog = eg.ConfigurationDialog(self, resizeable=True)

        #building dialog
        hidList = wx.ListCtrl(dialog, -1, pos=wx.DefaultPosition,
            size=wx.DefaultSize, style=wx.LC_REPORT | wx.LC_SINGLE_SEL)

        #create GUI
        hidList.InsertColumn(0, self.text.deviceName)
        hidList.InsertColumn(1, self.text.manufacturer)
        hidList.InsertColumn(2, self.text.connected)
       
       
        path = self.helper.GetDevicePath(noOtherPort,
            devicePath, vendorID, productID, versionNumber)
       
        #fill list
        devices = {}
        idx = 0
        for item in self.helper.deviceList:
            idx = hidList.InsertStringItem(sys.maxint, item[PRODUCT_STRING])
            hidList.SetStringItem(idx, 1, item[VENDOR_STRING])
            hidList.SetStringItem(idx, 2, self.text.yes)
            if item[DEVICE_PATH] == path:
                hidList.Select(idx)
            devices[idx] = item

        #add not connected device to bottom of list
        if not path:
            if not devicePath:
                #just select first entry on first start
                hidList.Select(0)
            else:
                item = {
                    DEVICE_PATH: devicePath,
                    VENDOR_ID: vendorID,
                    VENDOR_STRING: vendorString,
                    PRODUCT_ID: productID,
                    PRODUCT_STRING: productString,
                    VERSION_NUMBER: versionNumber,
                }
                idx = hidList.InsertStringItem(sys.maxint, item[PRODUCT_STRING])
                hidList.SetStringItem(idx, 1, item[VENDOR_STRING])
                hidList.SetStringItem(idx, 2, self.text.no)
                hidList.Select(idx)
                devices[idx] = item
           

        #layout
        for i in range(hidList.GetColumnCount()):
            hidList.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER)
            size = hidList.GetColumnWidth(i)
            hidList.SetColumnWidth(i, wx.LIST_AUTOSIZE)
            hidList.SetColumnWidth(i, max(size, hidList.GetColumnWidth(i) + 5))
       
        dialog.sizer.Add(hidList, 1, flag = wx.EXPAND)
       
        #sizers
        optionsSizer = wx.GridBagSizer(0, 5)

        #eventname
        optionsSizer.Add(
            wx.StaticText(dialog, -1, self.text.eventName),
            (0, 0),
            flag = wx.ALIGN_CENTER_VERTICAL)
        eventNameCtrl = wx.TextCtrl(dialog, value = eventName)
        eventNameCtrl.SetMaxLength(32)
        optionsSizer.Add(eventNameCtrl, (0, 1), (1, 2), flag = wx.EXPAND)
       
        #checkbox for no other port option
        noOtherPortCtrl = wx.CheckBox(dialog, -1, self.text.noOtherPort)
        noOtherPortCtrl.SetValue(noOtherPort)
        optionsSizer.Add(noOtherPortCtrl, (1, 0), (1, 3))

        #checkbox for enduring event option
        enduringEventsCtrl = wx.CheckBox(dialog, -1, self.text.enduringEvents)
        enduringEventsCtrl.SetValue(enduringEvents)
        optionsSizer.Add(enduringEventsCtrl, (2, 0), (1, 3))

        #checkbox for raw data events
        rawDataEventsCtrl = wx.CheckBox(dialog, -1, self.text.rawDataEvents)
        rawDataEventsCtrl.SetValue(rawDataEvents)
        optionsSizer.Add(rawDataEventsCtrl, (3, 0), (1, 3))
       
        dialog.sizer.Add(optionsSizer)

        def OnRawDataEventsChange(event):
            enduringEventsCtrl.Enable(not rawDataEventsCtrl.GetValue())
            event.Skip()
       
        def OnEnduringEventsChange(event):
            rawDataEventsCtrl.Enable(not enduringEventsCtrl.GetValue())
            event.Skip()

        OnRawDataEventsChange(wx.CommandEvent())
        OnEnduringEventsChange(wx.CommandEvent())
        rawDataEventsCtrl.Bind(wx.EVT_CHECKBOX, OnRawDataEventsChange)
        enduringEventsCtrl.Bind(wx.EVT_CHECKBOX, OnEnduringEventsChange)
       
        if dialog.AffirmedShowModal():
            device = devices[hidList.GetFirstSelected()]
            return (
                eventNameCtrl.GetValue(),
                enduringEventsCtrl.GetValue(),
                rawDataEventsCtrl.GetValue(),
                noOtherPortCtrl.GetValue(),
                device[DEVICE_PATH],
                device[VENDOR_ID],
                device[VENDOR_STRING],
                device[PRODUCT_ID],
                device[PRODUCT_STRING],
                device[VERSION_NUMBER]
            )
Last edited by Bartman on Thu Feb 22, 2007 9:03 pm, edited 3 times in total.
User avatar
Bitmonster
Site Admin
Posts: 2239
Joined: Mon Feb 06, 2006 10:28 pm

Post by Bitmonster »

Die Anzeige der Ger├ñte hat jetzt wirklich viel sch├Ânere Namen (gerade gemerkt, dass der Sconi auch ein HID-Device ist). Hat sich das Problem mit dem Dictionary als Ergebnis der Configure() in Luft aufgel├Âst, weil du jetzt nur noch ein Device behandelst?
Bartman
Plugin Developer
Posts: 881
Joined: Sun Feb 12, 2006 9:03 am

Post by Bartman »

Bitmonster wrote:Die Anzeige der Ger├ñte hat jetzt wirklich viel sch├Ânere Namen (gerade gemerkt, dass der Sconi auch ein HID-Device ist). Hat sich das Problem mit dem Dictionary als Ergebnis der Configure() in Luft aufgel├Âst, weil du jetzt nur noch ein Device behandelst?
jo
Ich habe noch das Problem, dass bei meinem Gamepad mit den Tasten keine enduringEvents hinbekomme, da fliegt zwar ein event, aber das hält nicht an.
Und bei meiner Tastatur klappt auch was noch nicht.

Was ist eigentlich aus dem Sconi-Plugin geworden?
User avatar
Bitmonster
Site Admin
Posts: 2239
Joined: Mon Feb 06, 2006 10:28 pm

Post by Bitmonster »

Ja, bei meinem Gampad sieht das auch etwas komisch aus. Bei jeder Änderung triggert es alle Values neu. Man müsste wohl alle Button-States und Values erst zwischenspeichern und dann schauen, welche sich bei der Nachricht wirklich geändert haben.
Bartman
Plugin Developer
Posts: 881
Joined: Sun Feb 12, 2006 9:03 am

Post by Bartman »

Bitmonster wrote:Ja, bei meinem Gampad sieht das auch etwas komisch aus. Bei jeder Änderung triggert es alle Values neu. Man müsste wohl alle Button-States und Values erst zwischenspeichern und dann schauen, welche sich bei der Nachricht wirklich geändert haben.
Ich habe jetzt absichtlich keine Events unterdr├╝ckt, da andere Plugins das auch nicht (mehr) machen. Daf├╝r ist ja der Haken unten.
Beim ersten Event würden auch eh alle Values getriggert, weil ich nicht weiß, auf welchem Wert die vorher stehen.
User avatar
Bitmonster
Site Admin
Posts: 2239
Joined: Mon Feb 06, 2006 10:28 pm

Post by Bitmonster »

Na ja, ich kriege zum Beispiel alle paar Sekunden diese Events:

Code: Select all

21:16:10 HID.Value.0 127
21:16:10 HID.Value.1 127
21:16:10 HID.Value.2 127
21:16:10 HID.Value.3 0
21:16:10 HID.Value.16 0
21:16:16 HID.Value.0 127
21:16:16 HID.Value.1 127
21:16:16 HID.Value.2 127
21:16:16 HID.Value.3 0
21:16:16 HID.Value.16 0
21:16:17 HID.Value.0 127
21:16:17 HID.Value.1 127
21:16:17 HID.Value.2 127
21:16:17 HID.Value.3 0
21:16:17 HID.Value.16 0
Es kommen also immer 5 Events gleichzeitig und es scheint sich nichts geändert zu haben. Und dadurch unterbrechen sie natürlich auch jeden EnduringEvent, der z.B. von einem Button noch aktiv ist.
Bartman
Plugin Developer
Posts: 881
Joined: Sun Feb 12, 2006 9:03 am

Post by Bartman »

mein Logitech macht das normalerweise nicht.
Ich sammle extra die Buttons ein und l├Âse erst Events f├╝r die analogen Values aus und dann zusammen die Buttons.
Der eine Teil meiner Logitechtastatur klappt auch nur mit den RawEvents sehe ich grade. Da gibt es keine Datenpakete von Windows und es wird nur eine Taste ausgewiesenn.

Ich habe den Code oben noch mal angepasst
Bartman
Plugin Developer
Posts: 881
Joined: Sun Feb 12, 2006 9:03 am

Post by Bartman »

Ich habe noch mal geschaut.
Wenn ich bei den analogen Events eg.TriggerEvent aufrufe, dann klappt es auch mit den enduring Events beim Gamepad.
Wenn ich in die Klasse RawReceiverPlugin schaue, dann wird da auch bei TriggerEvent ein PluginClass.TriggerEnduringEvent aufgerufen.
Hat es vielleicht damit zu tun? Was wird denn da eigentlich mit dem TimeOut gefummelt?
User avatar
Bitmonster
Site Admin
Posts: 2239
Joined: Mon Feb 06, 2006 10:28 pm

Post by Bitmonster »

RawReceiverPlugin.TriggerEvent l├Âst immer EnduringEvents aus, die nach dem Timeout oder bei dem Aufkommen eines anderen Events beendet werden. Also bei der Verwendung halten sie nur etwas l├ñnger an.

Um nun wirklich non-enduring-events in einem RawReceiverPlugin zu machen, kannst du ├╝ber PluginClass.TriggerEvent(self, suffix) statt self.TriggerEvent(suffix) gehen.

Nur damit ist das Problem der sich wiederholenden Value-Events noch nicht gel├Âst.
Please post software-related questions in the forum - PMs will only be answered, if really private, thanks!
Bartman
Plugin Developer
Posts: 881
Joined: Sun Feb 12, 2006 9:03 am

Post by Bartman »

noch ein paar Updates:

1) die Values werden jetzt gespeichert und nur bei Änderungen aufgerufen. Das mit den enduring Events klappt jetzt auch.
Eigentlich h├ñtte auch gleich von PluginClass erben k├Ânnen?!?!

2) Wenn der Gerätenamen bereits den Hersteller enthält wird nur noch der Gerätename als Label ausgegeben

3) Die Ger├ñte werden nur noch lesen ge├Âffnet.
Mir fällt auch grade keine sinnvolle Version ein an das Gerät Daten zu schicken. Da muss man das Device ja schon sehr genau kennen, auch wenn es ähnlich der Ausgabe Information für die Eingabe ausgibt.
User avatar
Bitmonster
Site Admin
Posts: 2239
Joined: Mon Feb 06, 2006 10:28 pm

Post by Bitmonster »

Mit der neuen Version bekomme ich nicht alle Geräte angezeigt. Mein Gamepad fehlt. Dieses hat keinen Hersteller-String sondern nur einen Device-String. Vielleicht liegt es daran.
Please post software-related questions in the forum - PMs will only be answered, if really private, thanks!
Post Reply