Problem with MessageData plugin
-
Hi guys~
My goal is detecting and get any keybord key pressed and released.
So my idea is useing MessageData.CoreMessage() and gui.GetInputEvent() to get which key was pressed and released.
But the problem is when i press some key , some time it can print the result, but mostly it can't .
I don't know if i do some mistakes, there is the code:import c4d from c4d import plugins pid = 20231019 pname = "msg_test" class MSG(plugins.MessageData): def GetTimer(self): return 100 # ms def CoreMessage(self, id, bc): if id == c4d.MSG_TIMER: if c4d.gui.GetInputEvent(c4d.BFM_INPUT_KEYBOARD, bc): key = bc[c4d.BFM_INPUT_CHANNEL] print(key) print (c4d.gui.Shortcut2String(bc[c4d.BFM_INPUT_QUALIFIER], bc[c4d.BFM_INPUT_CHANNEL])) return True if __name__ == '__main__': reg = plugins.RegisterMessagePlugin(id=pid, str=pname, info=0, dat=MSG())
-
Hey @gheyret,
Thank you for reaching out to us. What you do there does not match the description of what you want to do.
My goal is detecting and get any keybord key pressed and released.
What you do in your code is checking the current input state of the keyboard every 100 milliseconds. When the user happens to press the key in between your polling, i.e., the user already released the key when your function runs, you will detect nothing. This is even further complicated by the fact that timer events are not the most precise thing in the world and for requesting a stride of 100 ms, you will end up with an event queue which looks for example like this
92ms, 117ms, 81ms, 123ms, ...
.Core messages are the wrong choice for this, the natural message stream for this would be GUI messages; specifically the
BFM_INPUT
family. But for that you need a dialog or similar entity, and it must be in focus. In C++ there isSceneHookData
and its method KeyBoardInput which allows you to hook into the global keyboard input stream. ButSceneHookData
has never been exposed to Python.Maybe you can explain what you want to achieve on a functionality level, e.g., "create a new material everytime the user presses the 'm' key", so that we can see if there is some "out-of-the-box-thinking"-solution for your problem.
Cheers,
Ferdinand -
@ferdinand
oops , my bad, i forgot to delet the Timer in this test code. However, even if I delete the Timer, the above problem still exists.In fact, this is a pre-development feasibility test. My idea goes something like this: I have a pre-written toolset, and then users can bind these tool commands to the shortcut they want, and when the shortcut is pressed, the corresponding command will be executed.
And you sad the CoreMessage is wrong choice and SceneHookData is not available in python.
I want to know why the CoreMessage is wrong choice and is there have other way to get global keyboard input? -
Hey @gheyret ,
@gheyret said in Problem with MessageData plugin:
I want to know why the CoreMessage is wrong choice and is there have other way to get global keyboard input?
Because core messages are not the message stream for mouse and keyboard inputs. Core events covey things like the scene having been updated, or viewports or other parts of Cinema 4D being redrawn. Timer events are also conveyed as core messages. Your code cannot work and it is always hard to answer questions when users show us other code than the one they are using, but:
- You do what your code from above shows, hook into
MSG_TIMER
and register for100 ms
: I have explained above why this is error prone. - You do not hook into
MSG_TIMER
and instead evaluate the keyboard state every timeCoreMessage
is called (so on each core message event). This is even worse, because there is no guarantee that a core message is broadcasted at the same time when the user is typing. In fact, there is a good chance that you get core event starved when the user is typing, and you have no timer running which is forcing core messages.
As I said, the natural message stream for this is GUI messages, as Cinema 4D will call you there on its own when the user is making inputs (with
BFM_INPUT
as lined out above). But you need some form of UI implementation for that, and it only works when the user is focusing on that UI of yours. The thing which does what you want is aSceneHook
as they are meant to be the spider in the web kind of thing you are here after.I would recommend having a look at the Message Manual, it should clarify things.
You can get the global keyboard state, just as you do it. But what you cannot do is hook into the global input stream (get state: you pull state, stream: Cinema 4D pushes states to you).
SceneHookData
is sort of an exception, but as you can see in the C++ docs I linked to in my former post, you must be careful there too.Cheers,
Ferdinand - You do what your code from above shows, hook into
-