A file with extension .pyp is not a script but a plugin.
As far as I understand the script manager will only list scripts with extension .py
The .pyp file you have should be located in the plugins folder, and should then show up in the Extensions menu of Cinema4D.
You cannot make a plugin run from within the script manager.
Posts made by C4DS
Thanks for taking the time to respond, even during the weekend.
I must say this is quite embarrassing: I already had forgotten about the response in the other thread, and it's not even 3 weeks old.
I sincerely apologize for wasting your time with this duplicate thread.
I can confirm the GetInputState is working fine, no need to waste more of your time trying it out.
Thanks again.
As the topic title says, I am trying to detect a CTRL + RightMouseButton in a scenehook.
I managed to get this working in R20, as was discussed here:
https://plugincafe.maxon.net/topic/14149/detect-ctrl-rightmousebutton-in-scenehook
Trying the same with version 2023, still using the same code:
if (msg.GetInt32(BFM_INPUT_CHANNEL) == BFM_INPUT_MOUSERIGHT)
{
BaseContainer keyChannels;
if (GetInputEvent(BFM_INPUT_KEYBOARD, keyChannels))
{
Bool ctrlModifier = (keyChannels.GetInt32(BFM_INPUT_QUALIFIER) & QCTRL) != 0;
if (ctrlModifier)
{
ApplicationOutput("SceneHook - MouseInput: RMB + CTRL was pressed");
return true;
}
}
}
Unfortunately, the 'GetInputEvent' does not seem to get any result.
Tested with R25 and version 2023.1.3
I am using priority value of 2001.
Thanks @m_adam
I can confirm that the following does work with R20, R23 and 2023
Int32 MyDialog::Message(const BaseContainer& msg, BaseContainer& result)
{
BaseContainer keyChannels;
if (GetInputState(BFM_INPUT_KEYBOARD, QCTRL, keyChannels))
{
Bool ctrlModifier = (keyChannels.GetInt32(BFM_INPUT_QUALIFIER) & QCTRL) != 0;
I was reading the original R20 documentation, when the above question popped up.
Luckily, the latest online SDK documentation contains a BaseDocument Manual, where it mentions (if I understand it correctly) that KillDocument
is to be called to remove a BaseDocument from the list.
Which means KillDocument
should only be used if a BaseDocument was created and inserted in the list (via InsertBaseDocument
).
So, as long as I use IsolateObjects
without performing an InsertBaseDocument
I should be fine with calling BaseDocument::Free to free the obtained basedocument.
If I perform an IsolateObjects
and subsequently call InsertBaseDocument
then I should use KillDocument
.
Correct?
I am using IsolateObjects
to copy an object into a separate document in order to render a preview of the isolated object.
The documentation mentions "The caller owns the pointed document."
Do I simply need to perform a BaseDocument::Free
on the obtained document?
Or do I need to call KillDocument
?
The following works in R20
Int32 MyDialog::Message(const BaseContainer& msg, BaseContainer& result)
{
BaseContainer keyChannels;
if (GetInputEvent(BFM_INPUT_KEYBOARD, keyChannels))
{
const Int32 qualifier = keyChannels.GetInt32(BFM_INPUT_QUALIFIER);
ApplicationOutput("qualifier @", qualifier);
}
It shows a value '2' when I press CTRL key, '0' when I let go.
But in R23 (and above), I don't get any output in console window.
I am in a GeDialog and have a button that is by default disabled.
I want to enable it as long as CTRL key is being pressed.
I ma not familiar with PreferenceData
, but maybe the following might help you:
https://plugincafe.maxon.net/topic/13379/send-message-to-commanddata
In short: you let the PreferenceData call your CommandData's ExecuteSubID via a specific unique ID (similarly obtained from plugincafe as a pluginID).
The CommandData knows if that specific subID is called that it should react to a change of preferences.
Not the most elegant solution, and maybe there are ways to do this directly from PreferenceData, but as said I am not familiar with it.
If I remember correctly, most strings now need to be of type maxon::String. Can't remember in which version this was introduced (and that doesn't really matter).
Since then you could be using suffix _s
GePrint("Print this string..."_s);
There are different ways to output to the console, but I am now mainly using ApplicationOutput
.
Wasn't this listed in one of the "API Changes in Rxx"?
For a start some of the methods of CommandData
have received an additional argument GeDialog *parentManager
.
Apart from that I would suggest to just setup an R21 (and up) environment(s), port your project files to these, and start building the plugins.
From the errors you encounter you might find out what needs to be changed.
I know, this sounds quite a lot as "trial and error", but that's the only advice I have right now.
Unless you want to dig through all the SDK documentation's "API changes in R21, S22, R23, S24, R25, S26"
Once you have adapted your source files for macOS, you will be able to just take these over in your Windows (updated) projects, and build the plugins for PC.
EDIT:
I myself had set up on Windows an "SDK_Rxx" folder per release, and had extracted the SDK into these, together with the specific projecttool per release.
Same for macOS, but there I had prepared an external SSD with different OS versions, and XCode installs.
(example: Sierra -> R20 + XCode 9, High Sierra -> R21 + XCode 10, Mojave -> R23 + R25 + XCode 11)
No worries.
From your reply it seems this is a bug that is being tackled in a future release.
I don't mind this being fixed, but was hoping for another solution (or workaround) to be available for current and older versions (I am still on R20).
However, if using the MouseInput is the only way to go for detectig CTRL+RMB (with known limitations) then I guess we can close this topic.
Thank you for your time.
Thanks for the link to the updated page on the dev blog.
Can we please get an update on:
https://developers.maxon.net/docs/Cinema4DCPPSDK/html/page_maxonapi_dev_windows.html
As I still am mainly in "R20-timezone" I was trying to figure out which versions of Visual Studio are to be used to compile plugins for R23 and R25.
(Might be useful to also update the macOS page ... if needed)
Thanks.
@m_magalhaes said in Detect CTRL + RightMouseButton in SceneHook:
popup is not allowed for the tool
I didn't think of that one.
This does seems to mean that using SceneHook::MouseInput
to detect CTRL+RMB is probably not the right approach.
Is there another way to detect this action, no matter what tool is active?
@m_magalhaes said in Detect CTRL + RightMouseButton in SceneHook:
In fact, scenehook with a priority lower than 2000 will not be called if you are using another tool than move, scale or rotation.
That might be the case for ToolData
derived tools, but I can confirm that with a DescriptionToolData
derived tool active the scenehook (with priority 1000) does get called.
By default pressing the RightMouseButton in an editor view will show a popup menu. I would want to be able to trigger something similar, but without removing the possibility to trigger the default popup menu with RMB.
For this reason I came up with the combination of CTRL + RMB, which I detect in my SceneHook::MouseInput (as follows):
if (msg.GetInt32(BFM_INPUT_CHANNEL) == BFM_INPUT_MOUSERIGHT)
{
BaseContainer keyChannels;
if (GetInputEvent(BFM_INPUT_KEYBOARD, keyChannels))
{
Bool ctrlModifier = (keyChannels.GetInt32(BFM_INPUT_QUALIFIER) & QCTRL) != 0;
if (ctrlModifier)
{
ApplicationOutput("SceneHook - MouseInput: RMB + CTRL was pressed");
return true;
}
}
}
This is working fine when a move, rotate, scale tool is active. Even when an own custom created DescriptionTool plugin is active.
However, when the Live Selection tool is active, the code is not triggered.
At least not with the default "EXECUTIONPRIORITY_INITIAL" (=value 1000) I had provided when registering my scenehook plugin.
When I provide "EXECUTIONPRIORITY_ANIMATION (=value 2000) only then does the code get triggered, also when Live Selection tool is active.
return RegisterSceneHookPlugin(MY_SCENEHOOK_PLUGIN_ID, GeLoadString(IDS_MY_SCENEHOOK), 0, MySceneHook::Alloc, EXECUTIONPRIORITY_ANIMATION, 0);
Any value below 2000 just ignores to trigger the code when Live Selection tool is active.
Now, I can understand this is probably not a bug, but made on purpose. But why?
Why would the Live Selection tool have more "priority" then any other tool?
Note:
I am prototyping this with R20 (on Windows). Have not yet tested with later versions. Nor tried on macOS.
I didn't follow this topic in detail when it was originally posted, but I now noticed that in several of my plugins I do also use
GetInputState(BFM_INPUT_KEYBOARD, BFM_INPUT_CHANNEL, KB);
in order to check for possible qualifiers being pressed.
I guess this must have been picked up in the old forum, as the code is quite some years old.
It may not have been the intended way, but it seems to have been working all those years. At least till R21, as I haven't worked on more recent versions.
In the old forums there were quite some pieces of "example" code scattered around in posts, and back then it was a way to find out how to use some of the available functionality, due to limited documentation.
Speaking of documentation:
I just noticed that https://developers.maxon.net/docs/Cinema4DCPPSDK/html/class_scene_hook_data.html
lists MouseInput
and KeyboardInput
both pointing to "Input Events" for their last function argument
[in] msg The keyboard message container. See Input Events.
But the link just points back to the beginning of the page.
Where to find more details about these "Input Events" ???
- It depends where you want to know the tag was disabled? It also depends if you want to get triggered by the tag being enabled/disabled, or simply wants to check at given time if tag is enabled/disabled?
If you want to know from within the TagData-derived object the enable state of the tag you can (with a method receiving a GeListNode* node as argument) do:
BaseTag* tag = (BaseTag*)node;
Bool enabled = false;
if (tag)
{
GeData d;
tag->GetParameter(<your tag's ENABLE-id>, d, DESCFLAGS_GET::NONE);
enabled = d.GetBool();
}
...
If you want to get triggered by the change of state then:
Bool YourTagDataDerivedClass::Message(GeListNode* node, Int32 type, void* data)
{
if (type == MSG_DESCRIPTION_POSTSETPARAMETER)
{
DescriptionPostSetValue* postsetval = static_cast<DescriptionPostSetValue*>(data);
if (postsetval && (*postsetval->descid == DescID(<your tag's ENABLE-id>)))
... and same as above: you get the state of the enable-parameter
- or -
Bool YourTagDataDerivedClass::SetDParameter(GeListNode* node, const DescID& id, const GeData& t_data, DESCFLAGS_SET& flags)
{
if (!node)
return false;
const Int32& gadgetID = id[0].id;
switch (gadgetID)
{
case <your tag's ENABLE-id>:
enabled = t_data.GetBool();
- I guess the button in front of the "Enable" label is the keyframe button, so you can animate the tag being enabled/disabled over time.