Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PNP for tkinter #75

Open
IFXGAWU opened this issue May 3, 2022 · 4 comments
Open

PNP for tkinter #75

IFXGAWU opened this issue May 3, 2022 · 4 comments

Comments

@IFXGAWU
Copy link

IFXGAWU commented May 3, 2022

Hello,
I tried the pnp example for wx and it works fine for me.
Is there maybe an example available for tkinter available?
tkinter does not provide a handle, do you have some hints for me how to implement pnp for tkinter?
Thanks in advance,
GW

@rene-aguirre
Copy link
Owner

It seems there is a way to get the HWND, this looks like a good starting point: https://web.archive.org/web/20200731093951id_/http://effbot.org/tkinterbook/wm.htm#Tkinter.Wm.frame-method

@IFXGAWU
Copy link
Author

IFXGAWU commented May 5, 2022

Thanks for your very fast response!
Could you please give me an additional helping hand?

class MyFrame(ttk.Frame,hid.HidPnPWindowMixin):
# a device so we could easily discriminate wich devices to look at
my_hid_target = hid.HidDeviceFilter(vendor_id = target_vendor_id, product_id = target_product_id)

def __init__(self, parent):
    ttk.WmFrame.__init__(self,parent) #tkinter Frame has only 2 parameters
    # wx.Frame.__init__(self,parent,-1,"Re-plug your USB HID device, watch the command window!...")
    #             Frame(parent, id=ID_ANY, title="", pos=DefaultPosition, size=DefaultSize, style=DEFAULT_FRAME_STYLE, name=FrameNameStr)
    hid.HidPnPWindowMixin.__init__(self, self.GetHandle())
    ttk.EVT_CLOSE(self, self.on_close)

Result:
AttributeError: module 'tkinter.ttk' has no attribute 'WmFrame'

Do you have the time to check what's going wrong?
Or do I have to adapt the "HidPnPWindowMixin" for tkinter?
Thanks & BR

@rene-aguirre
Copy link
Owner

WMFrame seems to be legacy.

I check in a REPL session that a tkinter.Frame exposes a winfo_id() method, google shows this will be the frame HWND in Windows

@IFXGAWU
Copy link
Author

IFXGAWU commented Jul 13, 2022

Hello Rene,
It looks like that's how it works.

`#
"""
Plug and Play example

This script requires wxPython, but it could be easily (really!) changed
to work with any GUI working on windows, just make you you pass your frame window
handler to the HidPnPWindowMixin.init initialization function.

A hook will be inserted on the message handler so the window could be used as
a target for PnP events, for now this are HID class wise, this means you'll have
to test if your device 'plug' status has changed.
"""
from tkinter import *
from tkinter import ttk
import tkinter as tk
from tkinter import messagebox
from tkinter import filedialog
import tkinter as tk

import pywinusb.hid as hid
import sys
from time import sleep

feel free to test

target_vendor_id = 0x640
target_product_id = 0xA10

class MyFrame(ttk.Frame,hid.HidPnPWindowMixin):
# a device so we could easily discriminate wich devices to look at
my_hid_target = hid.HidDeviceFilter(vendor_id = target_vendor_id, product_id = target_product_id)

def __init__(self, parent):
    ttk.Frame.__init__(self,parent)
    # wx.Frame.__init__(self,parent,-1,"Re-plug your USB HID device, watch the command window!...")
    #             Frame(parent, id=ID_ANY, title="", pos=DefaultPosition, size=DefaultSize, style=DEFAULT_FRAME_STYLE, name=FrameNameStr)
    #hid.HidPnPWindowMixin.__init__(self, self.GetHandle())
    hid.HidPnPWindowMixin.__init__(self, self.winfo_id()) #or try winfo_id()
    #ttk.EVT_CLOSE(self, self.on_close)

    
    self.device = None #no hid device... yet

    # kick the pnp engine
    self.on_hid_pnp()

def on_hid_pnp(self, hid_event = None):
    """This function will be called on per class event changes, so we need
    to test if our device has being connected or is just gone"""
    # keep old reference for UI updates
    old_device = self.device

    if hid_event:
        print("Hey, a hid device just %s!" % hid_event)


    if hid_event == "connected":
        # test if our device is available
        if self.device:
            # see, at this point we could detect multiple devices!
            # but... we only want just one

            pass
        else:
            self.test_for_connection()
    elif hid_event == "disconnected":
        # the hid object is automatically closed on disconnection we just
        # test if still is plugged (important as the object might be
        # closing)
        if self.device and not self.device.is_plugged():
            self.device = None
            print("you removed my hid device!")
    else:
        # poll for devices
        self.test_for_connection()

    if old_device != self.device:
        # update ui
        pass

def test_for_connection(self):
    all_items =  MyFrame.my_hid_target.get_devices()
    if all_items:
        # at this point, what we decided to be a valid hid target is
        # already plugged
        if len(all_items) == 1:
            # this is easy, we only have a single hid device
            self.device = all_items[0]
        else:
            # at this point you might have multiple scenarios
            grouped_items = MyFrame.my_hid_target.get_devices_by_parent()
            print("%d devices now connected" % len(grouped_items))
            if len(grouped_items) > 1:
                # 1) Really you have multiple devices connected so, make
                # your rules, how do you help your user to handle multiple
                # devices?
                # maybe you here will find out wich is the new device, and
                # tag this device so is easily identified (i.e. the WiiMote
                # uses LEDs), or just your GUI shows some arbitrary
                # identification for the user (device 2 connected)
                pass
            else:
                # 2) We have a single physical device, but the descriptors
                # might might cause the OS to report is as multiple devices
                # (collections maybe) so, what would be your target device?
                # if you designed the device firmware, you already know the
                # answer...  otherwise one approach might be to browse the
                # hid usages for a particular target...  anyway, this could
                # be complex, especially handling multiple physical devices
                # that are reported as multiple hid paths (objects)...
                # so...  I recommend you creating a proxy class that is
                # able to handle all your 'per parent id' grouped devices,
                # (like a single .open() able to handle your buch of
                # HidDevice() items

                pass
            # but... we just arbitrarly select the first hid object path
            # (how creative!)
            self.device = all_items[0]
    if self.device:
        self.device.open()

        print("got my device: %s!" % repr(self.device))
        self.device.out_report = self.device.find_output_reports()[0]
        #sleep(2000)
        buffer[1] = 0x02   # Testdata
        buffer[2] = 0x00   # Testdata
        buffer[3] = 0x01   # Testdata
        buffer[4] = 0      # Testdata
        buffer[5] = 0      # Testdata
        self.device.out_report.set_raw_data(buffer)
        self.device.out_report.send()
    else:
        print("saddly my device is not here... yet :-( ")

def on_close(self, event):
    event.Skip()
    if self.device:
        self.device.close()

if name == "main":
buffer = [0x00] * 65
buffer[0] = 0x00

root = Tk()

#frame = Frame(root)
#frame.pack()


#frame = MyFrame(None)
frame = MyFrame(root)
frame.pack()

root.title("HID test pywinusb with TKINTER 2022/05/08")
root.geometry("1800x1000")
root.geometry("1920x1000+-8+0")

#frame.Show()   

root.mainloop()`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants