How to get mouse drag info from external through Python API?



  • Hi all, recently I need to finish a tiny plugin for C4D, the function is when I drag a file (mov jpeg c4d obj etc.) from external like windows explorer, or drag a path into C4D main window, the plugin will do something in C4D according to the file format extension, atthe beginning I want to open up a udp port, but I think this is not the best way, so if I want to write a callback detecting mouse drag from external, how to achieve that in python? I am quite new to c4d, I am a Maya TD...Thanks



  • hi @lotusab12, first all welcome in the plugincafe community.

    It's not possible to register a callback to such a global event in Cinema 4D. You could receive drag event from your own c4d.gui.GeDialog but that's it.
    Since you want to open a UDP port, I think it's probable that you want to run a server? If it's the case you may need to create a MessageData Plugin, but I will elaborate if it's the case just tell me.

    So your first need is to support a new file format, you can do this by creating a SceneLoader Plugin. Find an implementation example in py-xample_loader.

    When a user drops a file into Cinema 4D, all registered SceneLoaderData will be called. Since you don't really want to load a new scene (if I'm right), in your SceneLoaderData.Identify you can check if the file matches your pattern open your UDP port and return False.

    If you have any questions, please let me know.
    Cheers,
    Maxime.



  • This post is deleted!


  • @m_adam said in How to get mouse drag info from external through Python API?:

    hi @lotusab12, first all welcome in the plugincafe community.

    It's not possible to register a callback to such a global event in Cinema 4D. You could receive drag event from your own c4d.gui.GeDialog but that's it.
    Since you want to open a UDP port, I think it's probable that you want to run a server? If it's the case you may need to create a MessageData Plugin, but I will elaborate if it's the case just tell me.

    So your first need is to support a new file format, you can do this by creating a SceneLoader Plugin. Find an implementation example in py-xample_loader.

    When a user drops a file into Cinema 4D, all registered SceneLoaderData will be called. Since you don't really want to load a new scene (if I'm right), in your SceneLoaderData.Identify you can check if the file matches your pattern open your UDP port and return False.

    If you have any questions, please let me know.
    Cheers,
    Maxime.

    WoW, your feedback is full of detail! Awosome, really thanks for your kind and rapid reply, first of all I will just forget about open a UDP port, I will write a plugin first and follow your steps and read the document, next if I met any problem, I will ask you for future help, anyway thanks a lot man!

    Best
    Javier



  • @lotusab12 said in How to get mouse drag info from external through Python API?:

    @m_adam said in How to get mouse drag info from external through Python API?:

    hi @lotusab12, first all welcome in the plugincafe community.

    It's not possible to register a callback to such a global event in Cinema 4D. You could receive drag event from your own c4d.gui.GeDialog but that's it.
    Since you want to open a UDP port, I think it's probable that you want to run a server? If it's the case you may need to create a MessageData Plugin, but I will elaborate if it's the case just tell me.

    So your first need is to support a new file format, you can do this by creating a SceneLoader Plugin. Find an implementation example in py-xample_loader.

    When a user drops a file into Cinema 4D, all registered SceneLoaderData will be called. Since you don't really want to load a new scene (if I'm right), in your SceneLoaderData.Identify you can check if the file matches your pattern open your UDP port and return False.

    If you have any questions, please let me know.
    Cheers,
    Maxime.

    WoW, your feedback is full of detail! Awosome, really thanks for your kind and rapid reply, first of all I will just forget about open a UDP port, I will write a plugin first and follow your steps and read the document, next if I met any problem, I will ask you for future help, anyway thanks a lot man!

    Best
    Javier

    import c4d
    import socket
    from c4d.threading import C4DThread
    
    class A(C4DThread):
        sock = socket.socket(socket.AF_INIT, socket.SOCK_DGRAM)
        
        def Main(self):
            self.sock.bind(("localhost", 20015))
            while(True):
                data, addr = self.sock.recvfrom(1024)
    
        def End(self):
            self.sock.close()
    
    if __name__ == "__main__":
        thread = A()
        thread.Start()
    

    I have this piece of code in my simple plugin, my problem is since a while loop is keep running, after I close C4D, the cinema4d.exe is still runing behind the hood, so how can I kill this thread properly after I close Cinema4D application? Thanks.



  • Hi @lotusab12

    In such a thread you need to call TestBreak() in order to test if Cinema 4D tell your thread to stop.
    This will give us something like:

    def Main(self):
        self.sock.bind(("localhost", 20015))
        while(True):
            if self.TestBreak():
                server.close()
                self.End()
    
            data, addr = self.sock.recvfrom(1024)
    
    def End(self):
        self.sock.close()
    

    Another and probably safer version also is to define a timeout this way you can shut down your server if nothing happens since a given time lapse.

    Cheers,
    Maxime.



  • @m_adam said in How to get mouse drag info from external through Python API?:

    Hi @lotusab12

    In such a thread you need to call TestBreak() in order to test if Cinema 4D tell your thread to stop.
    This will give us something like:

    def Main(self):
        self.sock.bind(("localhost", 20015))
        while(True):
            if self.TestBreak():
                server.close()
                self.End()
    
            data, addr = self.sock.recvfrom(1024)
    
    def End(self):
        self.sock.close()
    

    Another and probably safer version also is to define a timeout this way you can shut down your server if nothing happens since a given time lapse.

    Cheers,
    Maxime.

    Thanks man, I will give it a try!



  • @m_adam said in How to get mouse drag info from external through Python API?:

    Hi @lotusab12

    In such a thread you need to call TestBreak() in order to test if Cinema 4D tell your thread to stop.
    This will give us something like:

    def Main(self):
        self.sock.bind(("localhost", 20015))
        while(True):
            if self.TestBreak():
                server.close()
                self.End()
    
            data, addr = self.sock.recvfrom(1024)
    
    def End(self):
        self.sock.close()
    

    Another and probably safer version also is to define a timeout this way you can shut down your server if nothing happens since a given time lapse.

    Cheers,
    Maxime.

    import c4d
    import socket
    from c4d.threading import C4DThread
    
    class A(C4DThread):
        sock = socket.socket(socket.AF_INIT, socket.SOCK_DGRAM)
        
        def Main(self):
            self.sock.bind(("localhost", 20015))
            while(True):
                if self.TestBreak():
                    self.End()
    
                data, addr = self.sock.recvfrom(1024)
    
        def End(self):
            self.sock.close()
    
    if __name__ == "__main__":
        thread = A()
        thread.Start()
    

    Hi Maxime, I tried TestBreak(), above are my code, but after I close Cinema4D, CINEMA4D.exe was still hunging up in Windows Task Monitor, it can not be killed properly, I tried to remove line "data, addr = self.sock.recvfrom(1024)" and add a "break" in "if TestBreak():", CINEMA4D.exe can be killed in Task Monitor, so please help me pointing out where I was wrong, it seems something interup with thread itself?

    PS: I don't know what does the line "server.close()" in your code mean, does it equal to self.sock.close()?



  • Hi sorry about the confusion of server.close I was referring to self.sock.close.

    After some tests the main issue with your code is currently recvfrom is blocking, meaning until it receives something all the code is blocked, so TestBreak is never called and the thread never ends.

    So using timeout solve the issue.

    import c4d
    import socket
    
    
    class A(c4d.threading.C4DThread):
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        end = False
        
        def Main(self):
                
            self.sock.bind(("localhost", 20014))
            while True:
    
                # use timeout to check for TestBreak()
                try:
                    self.sock.settimeout(1.0)
                    self.sock.listen(1)
                    conn, addr = self.sock.accept()
    
                    # connection  
                    print('Connection address:' + str(addr))
                
                    data = conn.recv(BUFFER_SIZE)
                    if not data:
                        print("Got no data.")
                        break
                    else:
                        print("received data:" + str(data))
                        print str(data)
                        self._data = str(data)
                        # DO SOMETHING
                
                    conn.close()
    
                # timeout
                except:
                    if self.TestBreak():
                        self.sock.close()
                        self.End()
                        return
                    continue
    
            self.sock.close()
    
    
    if __name__ == "__main__":
        threadedServer = A()
        threadedServer.Start()
    

    Cheers,
    Maxime.



  • @m_adam said in How to get mouse drag info from external through Python API?:

    Hi sorry about the confusion of server.close I was referring to self.sock.close.

    After some tests the main issue with your code is currently recvfrom is blocking, meaning until it receives something all the code is blocked, so TestBreak is never called and the thread never ends.

    So using timeout solve the issue.

    import c4d
    import socket
    
    
    class A(c4d.threading.C4DThread):
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        end = False
        
        def Main(self):
                
            self.sock.bind(("localhost", 20014))
            while True:
    
                # use timeout to check for TestBreak()
                try:
                    self.sock.settimeout(1.0)
                    self.sock.listen(1)
                    conn, addr = self.sock.accept()
    
                    # connection  
                    print('Connection address:' + str(addr))
                
                    data = conn.recv(BUFFER_SIZE)
                    if not data:
                        print("Got no data.")
                        break
                    else:
                        print("received data:" + str(data))
                        print str(data)
                        self._data = str(data)
                        # DO SOMETHING
                
                    conn.close()
    
                # timeout
                except:
                    if self.TestBreak():
                        self.sock.close()
                        self.End()
                        return
                    continue
    
            self.sock.close()
    
    
    if __name__ == "__main__":
        threadedServer = A()
        threadedServer.Start()
    

    Cheers,
    Maxime.

    Awosome, the whole script works very well now, thanks man, you help me quite a lot! mua~