SOLVED How to Register "Hot key" plugin in python?

Hello !
I see the "hotkey" plugin in cinema 4d like "Move Parent", and the shortcut is "7", and i need to press and hold down the shortcut key to execute the plugin.
(You can see the Type is Hotkey)
Snipaste_2021-09-16_15-32-35.jpg
So how do i register the "hotkey" plugin in python?
Actually i find some hotkey stuf like Command plugin flag in SDK;
Snipaste_2021-09-16_15-41-49.jpg
But i am not sure it's what i want, if it's what i want, how do i use it ? and how do i bind the shortcut key for the plugin ?
Thanks

I try to register a CommandDataPlugin with PLUGINFLAG_COMMAND_HOTKE flags,
and i assign a shortcut key like this ; .
But when i press the shortcut key anything doesn't happen.

I don't know is i did something is wrong?
How can i do it's work correctly?

And the examle code like this:

class Hotket(plugins.CommandData):
    def Execute(self, doc):
        print("Hotkey pressed")

        return True

if __name__ == '__main__':
    plugins.RegisterCommandPlugin(1208170,"Hotkey Test",c4d.PLUGINFLAG_COMMAND_HOTKEY,None,"",Hotket())

Hello !~~
I'm waiting...

Hello @gheyret,

thank you for reaching out to us and please excuse the slight delay. You are misunderstanding the purpose of PLUGINFLAG_COMMAND_HOTKEY, which admittedly is badly explained, and I also had to do some digging myself to understand how this is meant to be used. In bullet points:

  1. First of all, you do not need any special flags to assign a shortcut to your CommandData plugin. A simple PLUGINFLAG_SMALLNODE will be enough.
  2. Then there are these two flags PLUGINFLAG_COMMAND_HOTKEY and PLUGINFLAG_COMMAND_STICKY which are often used in conjunction internally. When you only pass PLUGINFLAG_COMMAND_HOTKEY, a command with your plugin id will be emitted continuously while the user is pressing the shortcut assigned to your plugin which did register with that flag. If also PLUGINFLAG_COMMAND_STICKY is being passed, there will only an opening and closing event for the key down and key up events.
  3. The Move Parent plugin you want to imitate is internally not a CommandData plugin, it simply registers its ID as an hotkey in a way not available to the public. But there are some CommandData plugins of ours which register as 'PLUGINFLAG_COMMAND_HOTKEY' or 'PLUGINFLAG_COMMAND_HOTKEY| PLUGINFLAG_COMMAND_STICKY'. And all these CommandData plugins then have one thing in common: They do nothing, or nothing related to the hotkey, as their Execute method will never be called or at least never be called in the context of the hotkey.
  4. So, hotkey means here that when you assign a shortcut to your plugin and press that shortcut key, a global hotkey message will be emitted. Which then can then be polled in other places. E.g., with EditorWindow.IsHotkeyDown or GeUserArea.IsHotkeyDown. Which is also why CommandData.Execute() will not be called when you pass the PLUGINFLAG_COMMAND_HOTKEY flag, since Cinema does assume you handle the associated logic in another place.
  5. So, to use PLUGINFLAG_COMMAND_HOTKEY, you will usually need at least two plugins. One that registers the hotkey and one that makes use of it. You could technically imagine a CommandData plugin which registers as a hotkey and the also makes use of the hotkey in its dialog window in some shape or form. But that will have the side effect that you cannot open the dialog with that hotkey, because CommandData.Execute() will never be called for that plugin when pressing the shortcut/hotkey. But you could still open the dialog by clicking with the mouse.
  6. If you want just some continuous execution, e.g., do XYZ while Shift + A are being pressed, you should just implement a normal CommandData and then poll in your CommandData.Execute() for these keys being pressed and do stuff while they are and stop doing when not. You can poll for the input state with c4d.gui.GetInputState and you can figure out the shortcuts assigned to your plugin with c4d.gui.GetShortcut, as shown in the code at the end of the posting.

The description for PLUGINFLAG_COMMAND_STICKY was either always wrong or is outdated, as it does indicate that 'PLUGINFLAG_COMMAND_HOTKEY | PLUGINFLAG_COMMAND_STICKY' will cause CommandData.Execute() to be called - which is not true.

I hope this helps,
Ferdinand

"""Example for retrieving the shortcuts for a plugin id.
"""

import c4d

def GetPluginShortcuts(pid: int) -> list[list[tuple[int]]]:
    """Retrieves the shortcuts for a plugin-id.
    
    Args:
        pid (int): The plugin id.
    
    Returns:
        list[list[tuple[int]]]: The shortcut sequences for the plugin.
    """
    # Get all shortcut containers for the plugin id.
    count = c4d.gui.GetShortcutCount()
    matches = [c4d.gui.GetShortcut(i) for i in range(count)
               if c4d.gui.GetShortcut(i)[c4d.SHORTCUT_PLUGINID] == pid]

    # build the shortcut data.
    result = []
    for item in matches:
        sequence = []
        for i in range(0, c4d.SHORTCUT_PLUGINID, 10):
            a, b = item[i], item[i+1]
            if isinstance(a, (int, float)):
                sequence.append((a, b))

        if sequence != []:
            result.append(sequence)
    return result


if __name__ == "__main__":
    # The shortcuts for your plugin id.
    for item in GetPluginShortcuts(1208170):
        for a, b in item:
            print (a, b, c4d.gui.Shortcut2String(a, b))
    # The shortcuts for the dissolve tool (multiple shortcuts)
    for item in GetPluginShortcuts(440000043):
        for a, b in item:
            print (a, b, c4d.gui.Shortcut2String(a, b))

Hi @ferdinand , Thank you very much for your detailed reply. I think it is very helpful to me.
Cheers!