Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Not reading ESC key

    PYTHON Development
    0
    30
    15.7k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      On 02/05/2016 at 02:25, xxxxxxxx wrote:

      Hello,

      as far as I can tell there is no way for this and when you think about it it should not work. At any time you can create a background thread with a BaseDocument that contains your plugin. So when the user presses the Esc button you cannot know if this is related to the execution of this specific task.

      The only proper way is to check the given BaseThread in TagData.Execute(). Check if the given thread stops with TestBreak().

      Best wishes,
      Sebastian

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 02/05/2016 at 02:34, xxxxxxxx wrote:

        Thank you.
        I will try to change my code into a user thread, then.

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 02/05/2016 at 03:10, xxxxxxxx wrote:

          However, shouldn't it be possible to read the keyboard, anyway?

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 02/05/2016 at 05:57, xxxxxxxx wrote:

            It is working in a different thread now.
            However, I still can't seem to abort it
            I override the TestDBreak method to this:

            def TestDBreak(self) :
                 state = c4d.BaseContainer()
                 if c4d.gui.GetInputState(c4d.BFM_INPUT_KEYBOARD, c4d.KEY_ESC, state) :
                      print "testing ESC"
                      if state[c4d.BFM_INPUT_VALUE]: return True
                 return False

            inside the Main in my thread I check for self.TestBreak() and it ALWAYS returns False.
            The Console never shows "testing ESC" (the print is there just for testing).
            How can I test for the user pressing Esc, so that I can return from my code prematurely?

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              On 02/05/2016 at 06:09, xxxxxxxx wrote:

              You understood it wrong. You don't have to make your own thread, just use TestBreak() on the
              BaseThread that is passed to TagData.Execute().

              GUI functions in the C4D API are not supposed to work from any other than the main thread.

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 02/05/2016 at 08:47, xxxxxxxx wrote:

                We don't know what Rui is doing in his "heavy Task".
                But does anyone else think that doing anything calculation intensive in a tag Plugin's Execute() method is a very, very, VERY bad idea?

                The tag's code executes upon every frame. And a tag is typically only used to read attribute values, or as a storage container. Which is a fast operation.
                The thought of crunching numbers upon every single frame in the Execute() method seems very wrong to me. The Message() method seems to me like a safer place to do that.
                But even so. The tag code needs to execute so fast from frame to frame that it just seems too dangerous to do anything too intensive in there.

                Can a tag really safely handle crunching code on the fly like that?

                -ScottA

                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

                  On 02/05/2016 at 08:56, xxxxxxxx wrote:

                  Well, it only calculates if the points change
                  So, once the calculation is done and there is no changes in the number or location of the vertexes, it just returns c4d.EXECUTIONRESULT_OK

                  Anyway, having it in a separate thread made it more efficient and I seem to be able to detect the ESC key now. I just have to use the bt thread to do it (thank you, Scott, Sebastian and Niklas).
                  Now I just have to fine tune the code to make it calculate only when it is needed, after the user halts it with ESC.

                  1 Reply Last reply Reply Quote 0
                  • H
                    Helper
                    last edited by

                    On 02/05/2016 at 09:00, xxxxxxxx wrote:

                    Sure it can safely take as much time as it needs. Only it will be annoying to the user if it takes too
                    much time. Just look at dynamics, they'll take many seconds per frame on a very large scene, too.
                    (And that they are computed from a SceneHook instead of a Tag plugin doesn't make a difference here).

                    -Niklas

                    1 Reply Last reply Reply Quote 0
                    • H
                      Helper
                      last edited by

                      On 02/05/2016 at 09:03, xxxxxxxx wrote:

                      Originally posted by xxxxxxxx

                      Anyway, having it in a separate thread made it more efficient

                      Are you talking about spawning a new C4DThread? I strongly believe that this won't be more efficient.
                      If anything, it should be the same performance (+ the overhead for spawning and waiting on the
                      thread) unless you're doing multithreading, which you can't in Python unless you do actual multiprocessing.

                      1 Reply Last reply Reply Quote 0
                      • H
                        Helper
                        last edited by

                        On 02/05/2016 at 09:09, xxxxxxxx wrote:

                        By "more efficient" I mean that as I adjust the parameters, the calculation stops and it starts again with the new values.
                        When it was in the main thread, I had to wait until the calculation was over (anything between .3 seconds to 20+ seconds) to adjust the parameters and see the new result.

                        1 Reply Last reply Reply Quote 0
                        • H
                          Helper
                          last edited by

                          On 02/05/2016 at 10:08, xxxxxxxx wrote:

                          Are you calling C4DThread.Wait() from Execute() (where I assume you are also starting the thread)?
                          Because you should. And if you check bt.TestBreak() frequently enough (thought you shouldn't do it
                          too frequently as it'll have performance impacts) you should get the same result ("responsiveness")

                          1 Reply Last reply Reply Quote 0
                          • H
                            Helper
                            last edited by

                            On 02/05/2016 at 10:45, xxxxxxxx wrote:

                            That is exactly what I'm doing
                            I'm still performing tests (to try to break it or spot any bugs) but it is working fine, so far.

                            1 Reply Last reply Reply Quote 0
                            • H
                              Helper
                              last edited by

                              On 02/05/2016 at 11:36, xxxxxxxx wrote:

                              I would love to see an actual example of this. Because I still don't see how you can catch a keypress in the Execute() method while the timeline is not moving?
                              And I don't see how using bt.TestBreak() solves that?

                              -ScottA

                              1 Reply Last reply Reply Quote 0
                              • H
                                Helper
                                last edited by

                                On 02/05/2016 at 14:11, xxxxxxxx wrote:

                                It goes something like this:

                                  
                                class MyThread(c4d.threading.C4DThread) :   
                                  
                                     bt = None   
                                  
                                     def Main(self) :   
                                  
                                          ...   
                                  
                                          if self.bt.TestBreak() : return   
                                  
                                          ...   
                                  
                                  
                                class my_plugin(plugins.TagData) :   
                                  
                                     thread = MyThread()   
                                  
                                     def Execute(self,tag,doc,op,bt,priority,flags) :   
                                  
                                          ...   
                                  
                                          MyThread.bt = bt   
                                          ...   
                                  
                                          self.thread.Start()   
                                          self.thread.Wait()   
                                
                                1 Reply Last reply Reply Quote 0
                                • H
                                  Helper
                                  last edited by

                                  On 02/05/2016 at 15:10, xxxxxxxx wrote:

                                  I'm trying to do this without making a new thread.
                                  Nicklas said we don't have to make a new thread. Just use bt.TestBreak(). But I don't see how to do that where it would allow us to capture a keypress.

                                  -ScottA

                                  1 Reply Last reply Reply Quote 0
                                  • H
                                    Helper
                                    last edited by

                                    On 02/05/2016 at 15:25, xxxxxxxx wrote:

                                    Well, I don't know either
                                    It is working for me, inside my user thread. But having a user thread is better in my particular case.
                                    As it is now, it seems to only check for Esc (luckily for me, it is what I want). But I would also like to know how to override the main TestBreak() method.

                                    1 Reply Last reply Reply Quote 0
                                    • H
                                      Helper
                                      last edited by

                                      On 03/05/2016 at 01:27, xxxxxxxx wrote:

                                      The BaseThread comes from the "Cinema 4D Core". It's implementation of TestBreak() does something like
                                      checking if the ESC key is pressed and returns True or False accordingly. Very likely, the event is saved somewhere
                                      in a queue or synchronized data structure from the main thread (since the thread itself can't check if the
                                      key is pressed, as we already figured).

                                      You're bound to the Cinema 4D way of cancelling such actions (ie. the ESC key) as you can not tell the
                                      BaseThread to check a different key in TestBreak() (that is hard coded somewhere in the C4D source
                                      where TagData.Execute() is called, since the BaseThread is passed to that function and can not be changed).

                                      It's the same mechanic to when you use the RenderDocument() function and pass it your own C4DThread,
                                      only that the context is reversed. Here, you call TestBreak() to check if the processing should stop, but
                                      the implementation of TestBreak() is not accessible to you. In RenderDocument(), it will call TestBreak()
                                      to check if the rendering should be aborted, and you can specify at what event exactly the rendering
                                      should stop by implemented C4DThread.TestDBreak().

                                      1 Reply Last reply Reply Quote 0
                                      • H
                                        Helper
                                        last edited by

                                        On 03/05/2016 at 08:23, xxxxxxxx wrote:

                                        That matches with what I'm seeing Niklas.
                                        It all comes down to GUI thread blocking. And the only way to get around it is to make your own thread.

                                        However...I still think it's a horrible idea to do this in a tag plugin.
                                        There's a good reason why some tags have a cache button on them. To do the number crunching and fill the tag with data first. Before the rest of the tag code is executed. Not doing them all at the same time. And then trying to stop it in mid execution if it takes too long.

                                        But I constantly break the rules myself. So I'm not in any position to throw stones. 😉

                                        -ScottA

                                        1 Reply Last reply Reply Quote 0
                                        • H
                                          Helper
                                          last edited by

                                          On 03/05/2016 at 08:32, xxxxxxxx wrote:

                                          Originally posted by xxxxxxxx

                                          That matches with what I'm seeing Niklas.
                                          It all comes down to GUI thread blocking. And the only way to get around it is to make your own thread.

                                          I am not sure I understand you correctly. Could you elaborate in more detail why you would need your own thread?

                                          Originally posted by xxxxxxxx

                                          However...I still think it's a horrible idea to do this in a tag plugin. 
                                          There's a good reason why some tags have a cache button on them. To do the number crunching and fill the tag with data first. Before the rest of the tag code is executed. Not doing them all at the same time. And then trying to stop it in mid execution if it takes too long.

                                          It usually all depends on numbers. If you accidentally cranked up that Subdivision Surface parameter
                                          into the nirvana, you're happy when you can stop the calculation by pressing the ESC key instead of
                                          waiting forever or shutting down your PC by force due to low/no free RAM.

                                          IMHO there is no general rule like "don't crunch too hard in Execute()", it just depends on what you're
                                          trying to accomplish, what the tag is doing/ must  be doing every frame, if it doesn't have the ability to
                                          do precalculations in any way.

                                          -Niklas

                                          1 Reply Last reply Reply Quote 0
                                          • H
                                            Helper
                                            last edited by

                                            On 03/05/2016 at 09:17, xxxxxxxx wrote:

                                            It's like you just said.
                                            There seems to be no way to catch a keypress (other than maybe Esc) unless we make our own thread.
                                            But I can't catch the Esc keypress from within the Execute() method using just the bt thread either.

                                            AFAIK. The subdivisions tag never "stops".
                                            The attributes are set to only accept a maximum of 1000 to prevent crashing.
                                            I don't know of any tag that actually "stops" the code execution using the bt thread. The very idea seems wrong headed to me.
                                            So if there is such a thing. I'd love to see an example of it.

                                            -ScottA

                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post