--- === plugins.cinema4D ===
--- Example Cinema4D Commands Plugin throw together for Sarah Kimberly Euschen.
--- Sorry, this looks way more complicated than it actually is... I promise!
--- You can learn more about Lua coding here:
--- https://dev.commandpost.io/lua/overview/
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Hammerspoon Extensions:
--------------------------------------------------------------------------------
local log = require("hs.logger").new("cinema4D")
local application = require("hs.application")
local eventtap = require("hs.eventtap")
local filter = require("hs.window").filter
--------------------------------------------------------------------------------
-- CommandPost Extensions:
--------------------------------------------------------------------------------
local commands = require("cp.commands")
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--- plugins.cinema4D.id() -> none
--- The ID used internally by CommandPost to identify CINEMA 4D.
--- plugins.cinema4D.appName() -> none
--- The application name used for Window Detection.
mod.appName = "CINEMA 4D Lite" -- You probably want to change this to something else, maybe just "CINEMA 4D"?
--- plugins.cinema4D.init() -> none
--- Initialises the Plugin
--------------------------------------------------------------------------------
-- Documentation: https://dev.commandpost.io/api/i18n/
--------------------------------------------------------------------------------
i18n.set("en.plugin_group_" .. mod.id, mod.appName) -- This sets the label used by the Group dropdown boxes.
i18n.set("en.shortcut_group_" .. mod.id, mod.appName) -- This sets the label used by the Shortcut Group dropdown box.
i18n.set("en." .. mod.id .. "_midi_label", mod.appName) -- This sets the label used in the Plugins Preference Page.
--------------------------------------------------------------------------------
-- Creates New CINEMA 4D Command Collection:
-- Documentation: https://dev.commandpost.io/api/cp/cp.commands.html
--------------------------------------------------------------------------------
mod.cmds = commands.new(mod.id)
--------------------------------------------------------------------------------
-- Subscribe to Window Events using `hs.window.filter`:
-- Documentation: https://dev.commandpost.io/api/hs/hs.window.filter.html
--------------------------------------------------------------------------------
mod._filter = filter.new{mod.appName}
:subscribe(filter.windowFocused, function()
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
log.df("Cinema 4D Focussed") -- This is just debugging code. It will write the result to the CommandPost Error Log.
mod._manager.groupStatus(mod.id, true)
:subscribe(filter.windowUnfocused, function()
--------------------------------------------------------------------------------
-- Window has lost focus:
--------------------------------------------------------------------------------
log.df("Cinema 4D Unfocussed") -- This is just debugging code. It will write the result to the CommandPost Error Log.
mod._manager.groupStatus(mod.id, false)
--------------------------------------------------------------------------------
-- Set up Application Watcher using `hs.application.watcher`:
-- Documentation: https://dev.commandpost.io/api/hs/hs.application.watcher.html
--------------------------------------------------------------------------------
mod._appWatcher = application.watcher.new(function(name, event, app)
if name == mod.appName then
if event == application.watcher.activated then
log.df("Cinema 4D Activated") -- This is just debugging code. It will write the result to the CommandPost Error Log.
mod._manager.groupStatus(mod.id, true)
elseif event == application.watcher.deactivated then
log.df("Cinema 4D Deactivated") -- This is just debugging code. It will write the result to the CommandPost Error Log.
mod._manager.groupStatus(mod.id, false)
--------------------------------------------------------------------------------
-- Using a table to generate shortcuts:
--------------------------------------------------------------------------------
["example1"] = { ["label"] = "Example 1",
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local app = application.frontmostApplication()
app:selectMenuItem({"CINEMA 4D Lite", "About CINEMA 4D Lite"})
["example2"] = { ["label"] = "Example 2",
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
local app = application.frontmostApplication()
app:selectMenuItem({"CINEMA 4D Lite", "About CINEMA 4D Lite"})
for id, v in pairs(shortcuts) do
i18n.set("en." .. id .. "_title", v.label)
mod.cmds:add(id):whenPressed(v.fn)
--------------------------------------------------------------------------------
-- Add "About Cinema 4D" Shortcut:
-- This is an example of how to trigger menu items.
--------------------------------------------------------------------------------
i18n.set("en.cinema4DHelpAbout_title", "About CINEMA 4D")
mod.cmds:add("cinema4DHelpAbout")
:activatedBy():ctrl():alt():cmd("1") -- This is the default shortcut.
local app = application.frontmostApplication()
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
app:selectMenuItem({"CINEMA 4D Lite", "About CINEMA 4D Lite"})
--------------------------------------------------------------------------------
-- This is an example of how to simulate keypresses.
--------------------------------------------------------------------------------
i18n.set("en.cinema4DNew_title", "New")
mod.cmds:add("cinema4DNew")
:activatedBy():ctrl():alt():cmd("2") -- This is the default shortcut.
log.df("New CINEMA 4D Shortcut Pressed!") -- This is just debugging code. It will write the result to the CommandPost Error Log.
--------------------------------------------------------------------------------
-- Simulates a keystroke:
-- Documentation: https://dev.commandpost.io/api/hs/hs.eventtap.html
--------------------------------------------------------------------------------
eventtap.keyStroke({"command"}, "n")
--------------------------------------------------------------------------------
-- Add "Trigger Python" Shortcut:
-- This is an example of how to trigger Terminal Commands:
--------------------------------------------------------------------------------
i18n.set("en.cinema4DPython_title", "Trigger Python")
mod.cmds:add("cinema4DPython")
:activatedBy():ctrl():alt():cmd("3") -- This is the default shortcut.
log.df("CINEMA 4D Python Shortcut Pressed!") -- This is just debugging code. It will write the result to the CommandPost Error Log.
--------------------------------------------------------------------------------
-- Triggers a Terminal command:
-- Documentation: https://dev.commandpost.io/api/hs/hs.html#execute
--------------------------------------------------------------------------------
local command = [[osascript -e 'tell app "]] .. mod.appName .. [[" to display dialog "Hello World"']]
--------------------------------------------------------------------------------
-- Setup Action Handler. This basically takes all our above "commands" and turns
-- them into actions (i.e. things that can be selected in the Console popups).
-- The reason we confusingly have both "Commands" and "Actions" is because of
-- the feature that allows you to control Final Cut Pro shortcuts from within
-- Final Cut Pro's own Command Editor. One day we'll make this cleaner.
-- https://dev.commandpost.io/api/plugins/plugins.core.action.handler.html
--------------------------------------------------------------------------------
i18n.set("en." .. mod.id .. "_cmds_action", mod.appName .. " Commands")
mod._handler = mod._actionmanager.addHandler(mod.id .. "_cmds", mod.id)
:onChoices(mod.onChoices)
:onExecute(mod.onExecute)
--- plugins.cinema4D.onChoices(choices) -> nothing
--- Adds available choices to the selection.
--- * `choices` - The `cp.choices` to add choices to.
function mod.onChoices(choices)
for _,cmd in pairs(mod.cmds:getAll()) do
local title = cmd:getTitle()
local group = cmd:getSubtitle()
if not group and cmd:getGroup() then
group = i18n(cmd:getGroup().."_group")
:subText(i18n("commandChoiceSubText", {group = group}))
--- plugins.cinema4D.getId(action) -> boolean
--- * `action` - A table representing the action, matching the following:
--- * `id` - The specific Command ID within the group.
--- * `true` if the action was executed successfully.
function mod.getId(action)
return string.format("%s:%s", ID, action.id)
--- plugins.cinema4D.execute(action) -> boolean
--- Executes the action with the provided parameters.
--- * `action` - A table representing the action, matching the following:
--- * `id` - The specific Command ID within the group.
--- * `true` if the action was executed successfully.
function mod.onExecute(action)
if cmdId == nil or cmdId == "" then
--------------------------------------------------------------------------------
-- No command ID provided:
--------------------------------------------------------------------------------
dialog.displayMessage(i18n("cmdIdMissingError"))
local cmd = group:get(cmdId)
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
dialog.displayMessage(i18n("cmdDoesNotExistError"), {id = cmdId})
--------------------------------------------------------------------------------
-- Ensure the command group is active:
--------------------------------------------------------------------------------
function() cmd:activated() end,
function() dialog.displayMessage(i18n("cmdGroupNotActivated"), {id = group.id}) end
--- plugins.cinema4D.reset() -> nothing
--- Resets the set of choices.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- This is the internal ID used by CommandPost:
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- This is the internal plugin group ID used by CommandPost:
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Below are a list of dependancies of other CommandPost plugins:
--------------------------------------------------------------------------------
["core.midi.manager"] = "manager",
["core.action.manager"] = "actionmanager",
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
function plugin.init(deps)
--------------------------------------------------------------------------------
-- Load dependancies to Module:
--------------------------------------------------------------------------------
mod._manager = deps.manager
mod._actionmanager = deps.actionmanager
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
function plugin.postInit()
-- You can do Plugin Post Initialisation stuff here if needed.