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 01/05/2016 at 05:12, xxxxxxxx wrote:

      I'm creating a plugin tag and, since some of the processes are slow, I wanted to implement a way to stop the calculation.
      So, I tried to read the ESC key and, if pressed, a variable is set to True and my calculation process finished.
      I tried to read the ESC key with this routine:

      def EscPressed() :

      msg = c4d.BaseContainer()
           if c4d.gui.GetInputState(c4d.BFM_INPUT_KEYBOARD,c4d.KEY_ESC, msg) :
                if msg[c4d.BFM_INPUT_VALUE]: return True

      return False

      And, in my main process, I have the stop variable set to False at the beginning.
      Inside the main loop, I have:

      if EscPressed() : stop=True

      and all my calculation only occur if stop==False

      I placed a print stop inside my main loop but it always prints False, no matter how hard and frequently I press the ESC key.
      What could be wrong?

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

        On 01/05/2016 at 12:16, xxxxxxxx wrote:

        I placed my keyboard reading code inside a Python scripting tag and doesn't work because, in order to make it execute the code constantly, I had to press Play. And, as soon as I press the Esc key, the play stops.

        Them I tried with a different code, to read the CONTROL key:

        def CtrlPressed() :
             bc = c4d.BaseContainer()
             mk = c4d.gui.GetInputState(c4d.BFM_INPUT_KEYBOARD,c4d.KEY_CONTROL, bc)
             if mk and bc[c4d.BFM_INPUT_VALUE]: return True
             return False

        It works inside a Python tag, but not inside my plugin
        It ALWAYS returns False.
        What could be happening?

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

          On 01/05/2016 at 12:29, xxxxxxxx wrote:

          This is the code I put in my tag plugin's Message() method.

                  bc = c4d.BaseContainer()  
                c4d.gui.GetInputState(c4d.BFM_INPUT_MOUSE, c4d.BFM_INPUT_MOUSELEFT, bc)  
                print bc[c4d.BFM_INPUT_VALUE]  
          

          It sort of works...But there's a catch. The tag needs to active.
          When I LMB click in the editor view. I do get a value change from 0 to 1. But only once.
          After that. I get nothing. Because the tag is no longer active.
          I'm guessing this is probably why you're not getting any return value.

          -ScottA

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

            On 01/05/2016 at 14:55, xxxxxxxx wrote:

            I placed...

            if CtrlPressed() : print "CTRL pressed"

            at the beginning of the Message method.
            And it works... but only outside the main calculation loop inside the Execute method, and that is where I wanted it to work
            So, if I make an adjustment to the parameters of my tag, it starts calculating. If I press the CTRL key, it shows nothing in the console but if I keep it pressed, it prints several "CTRL pressed" after finishing the calculation.
            So, it is not detecting the key when it should.
            Anyway, shouldn't the GetInputState return me the state of the keyboard/mouse as it is, in the moment the command is executed?

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

              On 01/05/2016 at 15:48, xxxxxxxx wrote:

              I changed my keyboard checking code to:

              def abort_key() :

              bc = c4d.BaseContainer()
                   if c4d.gui.GetInputState(c4d.BFM_INPUT_KEYBOARD,c4d.BFM_INPUT_CHANNEL,bc) :
                        print "+"
                        if (bc[c4d.BFM_INPUT_QUALIFIER] & c4d.QALT) :
                             print "ALT pressed"
                             return True
                   print "-"
                   return False

              Now I just check for the ALT key.
              And the only Console output I get is a lot of "-"
              So, the test is failing at the first if.
              The GetInputState(c4d.BFM_INPUT_KEYBOARD,c4d.BFM_INPUT_CHANNEL,bc) is returning False.

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

                On 01/05/2016 at 15:59, xxxxxxxx wrote:

                AFAIK. The code in a tag plugin only executes if the object it's on changes. Or the tag itself changes in some way.  Or their selection status changes.
                So if you are sitting there idle. And the host object or tag doesn't change. I can't see how the tag would ever be able to catch a key press event.

                Rather than using the keyboard. You can use a button gizmo on your tag.
                Clicking that button will update the tag and make the tag's code execute. Which will allow you to run your stop code.
                I don't see how you can use a key press in this scenario. But maybe someone else has an idea.

                -ScottA

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

                  On 01/05/2016 at 16:05, xxxxxxxx wrote:

                  I don't want to detect the keys while it is idle.
                  I need to detect the keys while executing my tag code (from the Execute method).
                  So, if the Execute method is running, it is because something changed in my tag. But the calculation inside the Execute method can, sometimes, take a few seconds to perform. That is why I wanted to test for some key combination (Esc would be the best) to stop my code execution.

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

                    On 01/05/2016 at 16:43, xxxxxxxx wrote:

                    I even tried sending a Message (a custom message, with the ID of my own plugin) to the Message method.
                    But, even there the code fails with the GetInputState(c4d.BFM_INPUT_KEYBOARD,c4d.BFM_INPUT_CHANNEL,bc) , that returns False

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

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

                      Hi Rui,  this works for me in a Python Scripting Tag:

                      import c4d
                      import time
                      #Welcome to the world of Python
                        
                      def test() :
                          state = c4d.BaseContainer()
                          if c4d.gui.GetInputState(c4d.BFM_INPUT_KEYBOARD, c4d.KEY_ESC, state) :
                              if state[c4d.BFM_INPUT_VALUE]:
                                  return True
                          return False
                        
                      def main() :
                          tstart = time.time()
                          while (time.time() - tstart) < 1.0:
                              if test() :
                                  print "STOPPED"
                                  break
                              time.sleep(0.1)
                      

                      However, you should prefer to use BaseThread.TestBreak() anyway.

                      import c4d
                      import time
                      #Welcome to the world of Python
                        
                      def main() :
                          tstart = time.time()
                          while (time.time() - tstart) < 1.0:
                              if bt.TestBreak() :
                                  print "STOPPED"
                                  break
                              time.sleep(0.1)
                      

                      Best,
                      Niklas

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

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

                        I can make it work on a Python Scripting Tag too.
                        It just doesn't work inside my plugin tag.

                        As for using BaseThread, I would have to move my whole code into a new thread, right?
                        Will that work on a tag plugin?

                        1 Reply Last reply Reply Quote 0
                        • 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
                                            • First post
                                              Last post