+ /// <summary>
+ /// True when this command is empty, false otherwise.
+ /// </summary>
+ property bool Empty;
+ /// <summary>
+ /// The initiator of the command
+ /// </summary>
+ property CecLogicalAddress Initiator;
+ /// <summary>
+ /// The destination of the command
+ /// </summary>
+ property CecLogicalAddress Destination;
+ /// <summary>
+ /// True when the ack bit is set, false otherwise
+ /// </summary>
+ property bool Ack;
+ /// <summary>
+ /// True when the eom bit is set, false otherwise
+ /// </summary>
+ property bool Eom;
+ /// <summary>
+ /// The CEC opcode of the command
+ /// </summary>
+ property CecOpcode Opcode;
+ /// <summary>
+ /// The parameters of this command
+ /// </summary>
+ property CecDatapacket ^ Parameters;
+ /// <summary>
+ /// True when an opcode is set, false otherwise (poll message)
+ /// </summary>
+ property bool OpcodeSet;
+ /// <summary>
+ /// The timeout to use when transmitting a command
+ /// </summary>
+ property int32_t TransmitTimeout;
+ };
+
+ /// <summary>
+ /// A key press that was received
+ /// </summary>
+ public ref class CecKeypress
+ {
+ public:
+ /// <summary>
+ /// Create a new key press instance
+ /// </summary>
+ /// <param name="keycode">The key code of this key press</param>
+ /// <param name="duration">The duration of this key press in milliseconds</param>
+ CecKeypress(CecUserControlCode keycode, unsigned int duration)
+ {
+ Keycode = keycode;
+ Duration = duration;
+ Empty = false;
+ }
+
+ /// <summary>
+ /// Create a new empty key press instance
+ /// </summary>
+ CecKeypress(void)
+ {
+ Keycode = CecUserControlCode::Unknown;
+ Duration = 0;
+ Empty = true;
+ }
+
+ /// <summary>
+ /// True when empty, false otherwise
+ /// </summary>
+ property bool Empty;
+ /// <summary>
+ /// The key code of this key press
+ /// </summary>
+ property CecUserControlCode Keycode;
+ /// <summary>
+ /// The duration of this key press in milliseconds
+ /// </summary>
+ property unsigned int Duration;
+ };
+
+ /// <summary>
+ /// A log message that libCEC generated
+ /// </summary>
+ public ref class CecLogMessage
+ {
+ public:
+ /// <summary>
+ /// Create a new log message
+ /// </summary>
+ /// <param name="message">The actual message</param>
+ /// <param name="level">The log level, so the application can choose what type information to display</param>
+ /// <param name="time">The timestamp of this message, in milliseconds after connecting</param>
+ CecLogMessage(System::String ^ message, CecLogLevel level, int64_t time)
+ {
+ Message = message;
+ Level = level;
+ Time = time;
+ Empty = false;
+ }
+
+ /// <summary>
+ /// Create a new empty log message
+ /// </summary>
+ CecLogMessage(void)
+ {
+ Message = "";
+ Level = CecLogLevel::None;
+ Time = 0;
+ Empty = true;
+ }
+
+ /// <summary>
+ /// True when empty, false otherwise.
+ /// </summary>
+ property bool Empty;
+ /// <summary>
+ /// The actual message
+ /// </summary>
+ property System::String ^Message;
+ /// <summary>
+ /// The log level, so the application can choose what type information to display
+ /// </summary>
+ property CecLogLevel Level;
+ /// <summary>
+ /// The timestamp of this message, in milliseconds after connecting
+ /// </summary>
+ property int64_t Time;
+ };
+
+ ref class CecCallbackMethods; //forward declaration
+
+ /// <summary>
+ /// The configuration that libCEC uses.
+ /// </summary>
+ public ref class LibCECConfiguration
+ {
+ public:
+ /// <summary>
+ /// Create a new configuration instance with default settings.
+ /// </summary>
+ LibCECConfiguration(void)
+ {
+ DeviceName = "";
+ DeviceTypes = gcnew CecDeviceTypeList();
+ AutodetectAddress = true;
+ PhysicalAddress = CEC_DEFAULT_PHYSICAL_ADDRESS;
+ BaseDevice = (CecLogicalAddress)CEC_DEFAULT_BASE_DEVICE;
+ HDMIPort = CEC_DEFAULT_HDMI_PORT;
+ ClientVersion = CecClientVersion::VersionPre1_5;
+ ServerVersion = CecServerVersion::VersionPre1_5;
+ TvVendor = CecVendorId::Unknown;
+
+ GetSettingsFromROM = false;
+ UseTVMenuLanguage = CEC_DEFAULT_SETTING_USE_TV_MENU_LANGUAGE == 1;
+ ActivateSource = CEC_DEFAULT_SETTING_ACTIVATE_SOURCE == 1;
+
+ WakeDevices = gcnew CecLogicalAddresses();
+ if (CEC_DEFAULT_SETTING_ACTIVATE_SOURCE == 1)
+ WakeDevices->Set(CecLogicalAddress::Tv);
+
+ PowerOffDevices = gcnew CecLogicalAddresses();
+ if (CEC_DEFAULT_SETTING_POWER_OFF_SHUTDOWN == 1)
+ PowerOffDevices->Set(CecLogicalAddress::Broadcast);
+
+ PowerOffScreensaver = CEC_DEFAULT_SETTING_POWER_OFF_SCREENSAVER == 1;
+ PowerOffOnStandby = CEC_DEFAULT_SETTING_POWER_OFF_ON_STANDBY == 1;
+
+ SendInactiveSource = CEC_DEFAULT_SETTING_SEND_INACTIVE_SOURCE == 1;
+ LogicalAddresses = gcnew CecLogicalAddresses();
+ FirmwareVersion = 1;
+ PowerOffDevicesOnStandby = CEC_DEFAULT_SETTING_POWER_OFF_DEVICES_STANDBY == 1;
+ ShutdownOnStandby = CEC_DEFAULT_SETTING_SHUTDOWN_ON_STANDBY == 1;
+ DeviceLanguage = "";
+ FirmwareBuildDate = gcnew System::DateTime(1970,1,1,0,0,0,0);
+ CECVersion = (CecVersion)CEC_DEFAULT_SETTING_CEC_VERSION;
+ AdapterType = CecAdapterType::Unknown;
+ }
+
+ /// <summary>
+ /// Change the callback method pointers in this configuration instance.
+ /// </summary>
+ /// <param name="callbacks">The new callbacks</param>
+ void SetCallbacks(CecCallbackMethods ^callbacks)
+ {
+ Callbacks = callbacks;
+ }
+
+ /// <summary>
+ /// Update this configuration with data received from libCEC
+ /// </summary>
+ /// <param name="config">The configuration that was received from libCEC</param>
+ void Update(const CEC::libcec_configuration &config)
+ {
+ DeviceName = gcnew System::String(config.strDeviceName);
+
+ for (unsigned int iPtr = 0; iPtr < 5; iPtr++)
+ DeviceTypes->Types[iPtr] = (CecDeviceType)config.deviceTypes.types[iPtr];
+
+ AutodetectAddress = config.bAutodetectAddress == 1;
+ PhysicalAddress = config.iPhysicalAddress;
+ BaseDevice = (CecLogicalAddress)config.baseDevice;
+ HDMIPort = config.iHDMIPort;
+ ClientVersion = (CecClientVersion)config.clientVersion;
+ ServerVersion = (CecServerVersion)config.serverVersion;
+ TvVendor = (CecVendorId)config.tvVendor;
+
+ // player specific settings
+ GetSettingsFromROM = config.bGetSettingsFromROM == 1;
+ UseTVMenuLanguage = config.bUseTVMenuLanguage == 1;
+ ActivateSource = config.bActivateSource == 1;
+
+ WakeDevices->Clear();
+ for (uint8_t iPtr = 0; iPtr <= 16; iPtr++)
+ if (config.wakeDevices[iPtr])
+ WakeDevices->Set((CecLogicalAddress)iPtr);
+
+ PowerOffDevices->Clear();
+ for (uint8_t iPtr = 0; iPtr <= 16; iPtr++)
+ if (config.powerOffDevices[iPtr])
+ PowerOffDevices->Set((CecLogicalAddress)iPtr);
+
+ PowerOffScreensaver = config.bPowerOffScreensaver == 1;
+ PowerOffOnStandby = config.bPowerOffOnStandby == 1;
+
+ if (ServerVersion >= CecServerVersion::Version1_5_1)
+ SendInactiveSource = config.bSendInactiveSource == 1;
+
+ if (ServerVersion >= CecServerVersion::Version1_5_3)
+ {
+ LogicalAddresses->Clear();
+ for (uint8_t iPtr = 0; iPtr <= 16; iPtr++)
+ if (config.logicalAddresses[iPtr])
+ LogicalAddresses->Set((CecLogicalAddress)iPtr);
+ }
+
+ if (ServerVersion >= CecServerVersion::Version1_6_0)
+ {
+ FirmwareVersion = config.iFirmwareVersion;
+ PowerOffDevicesOnStandby = config.bPowerOffDevicesOnStandby == 1;
+ ShutdownOnStandby = config.bShutdownOnStandby == 1;
+ }
+
+ if (ServerVersion >= CecServerVersion::Version1_6_2)
+ {
+ DeviceLanguage = gcnew System::String(config.strDeviceLanguage);
+ FirmwareBuildDate = gcnew System::DateTime(1970,1,1,0,0,0,0);
+ FirmwareBuildDate = FirmwareBuildDate->AddSeconds(config.iFirmwareBuildDate);
+ }
+
+ if (ServerVersion >= CecServerVersion::Version1_6_3)
+ MonitorOnlyClient = config.bMonitorOnly == 1;
+
+ if (ServerVersion >= CecServerVersion::Version1_8_0)
+ CECVersion = (CecVersion)config.cecVersion;
+
+ if (ServerVersion >= CecServerVersion::Version1_8_2)
+ AdapterType = (CecAdapterType)config.adapterType;
+ }
+
+ /// <summary>
+ /// The device name to use on the CEC bus
+ /// </summary>
+ property System::String ^ DeviceName;
+
+ /// <summary>
+ /// The device type(s) to use on the CEC bus for libCEC
+ /// </summary>
+ property CecDeviceTypeList ^ DeviceTypes;
+
+ /// <summary>
+ /// True to try to autodetect the physical address, false otherwise
+ /// </summary>
+ property bool AutodetectAddress;
+
+ /// <summary>
+ /// The physical address that libCEC uses on the CEC bus
+ /// </summary>
+ property uint16_t PhysicalAddress;
+
+ /// <summary>
+ /// The logical address of the device to which the CEC adapter is connected, only used when PhysicalAddress isn't set
+ /// </summary>
+ property CecLogicalAddress BaseDevice;
+
+ /// <summary>
+ /// The hdmi port number on the device to which the CEC adapter is connected, only used when PhysicalAddress isn't set
+ /// </summary>
+ property uint8_t HDMIPort;
+
+ /// <summary>
+ /// The client API version to use
+ /// </summary>
+ property CecClientVersion ClientVersion;
+
+ /// <summary>
+ /// The version of libCEC
+ /// </summary>
+ property CecServerVersion ServerVersion;
+
+ /// <summary>
+ /// Override the vendor ID of the TV when set (for quirks mode)
+ /// </summary>
+ property CecVendorId TvVendor;
+
+ /// <summary>
+ /// True to read the settings from the EEPROM, which possibly override the settings passed here
+ /// </summary>
+ property bool GetSettingsFromROM;
+
+ /// <summary>
+ /// Use the language setting of the TV in the client application. Must be implemented by the client application.
+ /// </summary>
+ property bool UseTVMenuLanguage;
+
+ /// <summary>
+ /// Make libCEC the active source when starting the client application
+ /// </summary>
+ property bool ActivateSource;
+
+ /// <summary>
+ /// List of devices to send a power on command to when starting the client application
+ /// </summary>
+ property CecLogicalAddresses ^WakeDevices;
+
+ /// <summary>
+ /// List of devices to send a standby command to when exiting the client application
+ /// </summary>
+ property CecLogicalAddresses ^PowerOffDevices;
+
+ /// <summary>
+ /// Send standby commands when the client application activates the screensaver. Must be implemented by the client application.
+ /// </summary>
+ property bool PowerOffScreensaver;
+
+ /// <summary>
+ /// Power off the PC when the TV powers off. Must be implemented by the client application.
+ /// </summary>
+ property bool PowerOffOnStandby;
+
+ /// <summary>
+ /// Send an inactive source message when exiting the client application.
+ /// </summary>
+ property bool SendInactiveSource;
+
+ /// <summary>
+ /// The list of logical addresses that libCEC is using
+ /// </summary>
+ property CecLogicalAddresses ^LogicalAddresses;
+
+ /// <summary>
+ /// The firmware version of the adapter to which libCEC is connected
+ /// </summary>
+ property uint16_t FirmwareVersion;
+
+ /// <summary>
+ /// Send standby commands when the client application activates standby mode (S3). Must be implemented by the client application.
+ /// </summary>
+ property bool PowerOffDevicesOnStandby;
+ property bool ShutdownOnStandby;
+
+ /// <summary>
+ /// True to start a monitor-only client, false to start a standard client.
+ /// </summary>
+ property bool MonitorOnlyClient;
+
+ /// <summary>
+ /// The language code of the menu language that libCEC reports to other devices.
+ /// </summary>
+ property System::String ^ DeviceLanguage;
+
+ /// <summary>
+ /// The callback methods to use.
+ /// </summary>
+ property CecCallbackMethods ^ Callbacks;
+
+ /// <summary>
+ /// The build date of the firmware.
+ /// </summary>
+ property System::DateTime ^ FirmwareBuildDate;
+
+ /// <summary>
+ /// The CEC version that libCEC uses.
+ /// </summary>
+ property CecVersion CECVersion;
+
+ /// <summary>
+ /// The type of adapter that libCEC is connected to.
+ /// </summary>
+ property CecAdapterType AdapterType;
+ };
+
+ // the callback methods are called by unmanaged code, so we need some delegates for this
+#pragma unmanaged
+ // unmanaged callback methods
+ typedef int (__stdcall *LOGCB) (const CEC::cec_log_message &message);
+ typedef int (__stdcall *KEYCB) (const CEC::cec_keypress &key);
+ typedef int (__stdcall *COMMANDCB)(const CEC::cec_command &command);
+ typedef int (__stdcall *CONFIGCB) (const CEC::libcec_configuration &config);
+ typedef int (__stdcall *ALERTCB) (const CEC::libcec_alert, const CEC::libcec_parameter &data);
+ typedef int (__stdcall *MENUCB) (const CEC::cec_menu_state newVal);
+ typedef void (__stdcall *ACTICB) (const CEC::cec_logical_address logicalAddress, const uint8_t bActivated);
+
+ /// <summary>
+ /// libCEC callback methods. Unmanaged code.
+ /// </summary>
+ typedef struct
+ {
+ /// <summary>
+ /// Log message callback
+ /// </summary>
+ LOGCB logCB;
+ /// <summary>
+ /// Key press/release callback
+ /// </summary>
+ KEYCB keyCB;
+ /// <summary>
+ /// Raw CEC data callback
+ /// </summary>
+ COMMANDCB commandCB;
+ /// <summary>
+ /// Updated configuration callback
+ /// </summary>
+ CONFIGCB configCB;
+ /// <summary>
+ /// Alert message callback
+ /// </summary>
+ ALERTCB alertCB;
+ /// <summary>
+ /// Menu status change callback
+ /// </summary>
+ MENUCB menuCB;
+ /// <summary>
+ /// Source (de)activated callback
+ /// </summary>
+ ACTICB sourceActivatedCB;
+ } UnmanagedCecCallbacks;
+
+ static PLATFORM::CMutex g_callbackMutex;
+ static std::vector<UnmanagedCecCallbacks> g_unmanagedCallbacks;
+ static CEC::ICECCallbacks g_cecCallbacks;
+
+ /// <summary>
+ /// Called by libCEC to send back a log message to the application
+ /// </summary>
+ /// <param name="cbParam">Pointer to the callback struct</param>
+ /// <param name="message">The log message</param>
+ /// <return>1 when handled, 0 otherwise</return>
+ int CecLogMessageCB(void *cbParam, const CEC::cec_log_message &message)
+ {
+ if (cbParam)
+ {
+ size_t iPtr = (size_t)cbParam;
+ PLATFORM::CLockObject lock(g_callbackMutex);
+ if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+ return g_unmanagedCallbacks[iPtr].logCB(message);
+ }
+ return 0;
+ }
+
+ /// <summary>
+ /// Called by libCEC to send back a key press or release to the application
+ /// </summary>
+ /// <param name="cbParam">Pointer to the callback struct</param>
+ /// <param name="key">The key press command that libCEC received</param>
+ /// <return>1 when handled, 0 otherwise</return>
+ int CecKeyPressCB(void *cbParam, const CEC::cec_keypress &key)
+ {
+ if (cbParam)
+ {
+ size_t iPtr = (size_t)cbParam;
+ PLATFORM::CLockObject lock(g_callbackMutex);
+ if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+ return g_unmanagedCallbacks[iPtr].keyCB(key);
+ }
+ return 0;
+ }
+
+ /// <summary>
+ /// Called by libCEC to send back raw CEC data to the application
+ /// </summary>
+ /// <param name="cbParam">Pointer to the callback struct</param>
+ /// <param name="command">The raw CEC data</param>
+ /// <return>1 when handled, 0 otherwise</return>
+ int CecCommandCB(void *cbParam, const CEC::cec_command &command)
+ {
+ if (cbParam)
+ {
+ size_t iPtr = (size_t)cbParam;
+ PLATFORM::CLockObject lock(g_callbackMutex);
+ if (iPtr >= 0 && iPtr < g_unmanagedCallbacks.size())
+ return g_unmanagedCallbacks[iPtr].commandCB(command);
+ }
+ return 0;
+ }
+
+ /// <summary>
+ /// Called by libCEC to send back an updated configuration to the application
+ /// </summary>
+ /// <param name="cbParam">Pointer to the callback struct</param>
+ /// <param name="config">The new configuration</param>
+ /// <return>1 when handled, 0 otherwise</return>