#include "COM/Com_Protocol.h" namespace { constexpr quint8 kProtoWireVarint = 0; constexpr quint8 kProtoWireFixed64 = 1; constexpr quint8 kProtoWireBytes = 2; constexpr quint8 kProtoWireFixed32 = 5; constexpr quint32 kFieldHelloReq = 1; constexpr quint32 kFieldHelloRsp = 2; constexpr quint32 kFieldBitmap = 3; constexpr quint32 kFieldFunctionKeyEvent = 4; constexpr quint32 kFieldLedState = 5; constexpr quint32 kFieldTimeSync = 6; constexpr quint32 kFieldThemeRgb = 7; constexpr quint32 kFieldAck = 8; constexpr quint32 kFieldError = 9; constexpr quint16 kUsageModifierFirst = 0x00E0; constexpr quint16 kUsageModifierLast = 0x00E7; constexpr quint16 kUsageNormalLast = 0x00DF; constexpr int kUsageBitmapSize = 29; bool Com_Protocol_ReadVarint(const QByteArray& Bytes, int* p_Offset, quint64* p_Value) { quint64 Value = 0; int Shift = 0; int Offset = *p_Offset; while (Offset < Bytes.size()) { const quint8 Byte = static_cast(Bytes.at(Offset++)); Value |= static_cast(Byte & 0x7FU) << Shift; if ((Byte & 0x80U) == 0U) { *p_Offset = Offset; *p_Value = Value; return true; } Shift += 7; if (Shift >= 64) { return false; } } return false; } bool Com_Protocol_ReadKey( const QByteArray& Bytes, int* p_Offset, quint32* p_FieldNumber, quint8* p_WireType) { quint64 Key = 0; if (!Com_Protocol_ReadVarint(Bytes, p_Offset, &Key)) { return false; } *p_FieldNumber = static_cast(Key >> 3); *p_WireType = static_cast(Key & 0x07U); return *p_FieldNumber > 0; } bool Com_Protocol_ReadLengthDelimited( const QByteArray& Bytes, int* p_Offset, QByteArray* p_Value) { quint64 Length = 0; if (!Com_Protocol_ReadVarint(Bytes, p_Offset, &Length)) { return false; } if ((Length > static_cast(Bytes.size())) || (*p_Offset > Bytes.size() - static_cast(Length))) { return false; } *p_Value = Bytes.mid(*p_Offset, static_cast(Length)); *p_Offset += static_cast(Length); return true; } bool Com_Protocol_ReadFixed32(const QByteArray& Bytes, int* p_Offset, quint32* p_Value) { if (*p_Offset > Bytes.size() - 4) { return false; } quint32 Value = 0; for (int Index = 0; Index < 4; ++Index) { Value |= static_cast( static_cast(Bytes.at(*p_Offset + Index))) << (Index * 8); } *p_Offset += 4; *p_Value = Value; return true; } bool Com_Protocol_ReadFixed64(const QByteArray& Bytes, int* p_Offset, quint64* p_Value) { if (*p_Offset > Bytes.size() - 8) { return false; } quint64 Value = 0; for (int Index = 0; Index < 8; ++Index) { Value |= static_cast( static_cast(Bytes.at(*p_Offset + Index))) << (Index * 8); } *p_Offset += 8; *p_Value = Value; return true; } bool Com_Protocol_SkipField(const QByteArray& Bytes, int* p_Offset, quint8 WireType) { switch (WireType) { case kProtoWireVarint: { quint64 Dummy = 0; return Com_Protocol_ReadVarint(Bytes, p_Offset, &Dummy); } case kProtoWireFixed64: if (*p_Offset > Bytes.size() - 8) { return false; } *p_Offset += 8; return true; case kProtoWireBytes: { QByteArray Dummy; return Com_Protocol_ReadLengthDelimited(Bytes, p_Offset, &Dummy); } case kProtoWireFixed32: if (*p_Offset > Bytes.size() - 4) { return false; } *p_Offset += 4; return true; default: return false; } } void Com_Protocol_AppendVarint(QByteArray* p_Bytes, quint64 Value) { do { quint8 Byte = static_cast(Value & 0x7FU); Value >>= 7; if (Value != 0) { Byte = static_cast(Byte | 0x80U); } p_Bytes->append(static_cast(Byte)); } while (Value != 0); } void Com_Protocol_AppendKey(QByteArray* p_Bytes, quint32 FieldNumber, quint8 WireType) { Com_Protocol_AppendVarint( p_Bytes, (static_cast(FieldNumber) << 3) | static_cast(WireType)); } void Com_Protocol_AppendUInt32Field(QByteArray* p_Bytes, quint32 FieldNumber, quint32 Value) { Com_Protocol_AppendKey(p_Bytes, FieldNumber, kProtoWireVarint); Com_Protocol_AppendVarint(p_Bytes, Value); } void Com_Protocol_AppendSInt32Field(QByteArray* p_Bytes, quint32 FieldNumber, qint32 Value) { const quint32 ZigZag = static_cast( (static_cast(Value) << 1) ^ static_cast(Value >> 31)); Com_Protocol_AppendUInt32Field(p_Bytes, FieldNumber, ZigZag); } void Com_Protocol_AppendFixed32Field(QByteArray* p_Bytes, quint32 FieldNumber, quint32 Value) { Com_Protocol_AppendKey(p_Bytes, FieldNumber, kProtoWireFixed32); for (int Index = 0; Index < 4; ++Index) { p_Bytes->append(static_cast((Value >> (Index * 8)) & 0xFFU)); } } void Com_Protocol_AppendFixed64Field(QByteArray* p_Bytes, quint32 FieldNumber, quint64 Value) { Com_Protocol_AppendKey(p_Bytes, FieldNumber, kProtoWireFixed64); for (int Index = 0; Index < 8; ++Index) { p_Bytes->append(static_cast((Value >> (Index * 8)) & 0xFFU)); } } void Com_Protocol_AppendBytesField( QByteArray* p_Bytes, quint32 FieldNumber, const QByteArray& Value) { Com_Protocol_AppendKey(p_Bytes, FieldNumber, kProtoWireBytes); Com_Protocol_AppendVarint(p_Bytes, static_cast(Value.size())); p_Bytes->append(Value); } quint32 Com_Protocol_FieldNumberForType(Com_Enum_ProtocolType Type) { switch (Type) { case Com_Enum_ProtocolType_HelloReq: return kFieldHelloReq; case Com_Enum_ProtocolType_HelloRsp: return kFieldHelloRsp; case Com_Enum_ProtocolType_Bitmap: return kFieldBitmap; case Com_Enum_ProtocolType_FunctionKeyEvent: return kFieldFunctionKeyEvent; case Com_Enum_ProtocolType_LedState: return kFieldLedState; case Com_Enum_ProtocolType_TimeSync: return kFieldTimeSync; case Com_Enum_ProtocolType_ThemeRgb: return kFieldThemeRgb; case Com_Enum_ProtocolType_Ack: return kFieldAck; case Com_Enum_ProtocolType_Error: return kFieldError; default: return 0; } } Com_Enum_ProtocolType Com_Protocol_TypeForFieldNumber(quint32 FieldNumber) { switch (FieldNumber) { case kFieldHelloReq: return Com_Enum_ProtocolType_HelloReq; case kFieldHelloRsp: return Com_Enum_ProtocolType_HelloRsp; case kFieldBitmap: return Com_Enum_ProtocolType_Bitmap; case kFieldFunctionKeyEvent: return Com_Enum_ProtocolType_FunctionKeyEvent; case kFieldLedState: return Com_Enum_ProtocolType_LedState; case kFieldTimeSync: return Com_Enum_ProtocolType_TimeSync; case kFieldThemeRgb: return Com_Enum_ProtocolType_ThemeRgb; case kFieldAck: return Com_Enum_ProtocolType_Ack; case kFieldError: return Com_Enum_ProtocolType_Error; default: return Com_Enum_ProtocolType_None; } } QByteArray Com_Protocol_EncodeEnvelope(Com_Enum_ProtocolType Type, const QByteArray& MessageBytes) { QByteArray PacketBody; const quint32 FieldNumber = Com_Protocol_FieldNumberForType(Type); if ((FieldNumber == 0) || MessageBytes.isEmpty()) { return PacketBody; } Com_Protocol_AppendBytesField(&PacketBody, FieldNumber, MessageBytes); return PacketBody; } bool Com_Protocol_DecodeEnvelope( const QByteArray& PacketBody, Com_Enum_ProtocolType* p_Type, QByteArray* p_MessageBytes) { int Offset = 0; while (Offset < PacketBody.size()) { quint32 FieldNumber = 0; quint8 WireType = 0; if (!Com_Protocol_ReadKey(PacketBody, &Offset, &FieldNumber, &WireType)) { return false; } const Com_Enum_ProtocolType Type = Com_Protocol_TypeForFieldNumber(FieldNumber); if (Type == Com_Enum_ProtocolType_None) { if (!Com_Protocol_SkipField(PacketBody, &Offset, WireType)) { return false; } continue; } if (WireType != kProtoWireBytes) { return false; } QByteArray MessageBytes; if (!Com_Protocol_ReadLengthDelimited(PacketBody, &Offset, &MessageBytes)) { return false; } *p_Type = Type; *p_MessageBytes = MessageBytes; return true; } return false; } bool Com_Protocol_DecodeEnvelopeForExpectedType( const QByteArray& PacketBody, Com_Enum_ProtocolType ExpectedType, QByteArray* p_MessageBytes) { Com_Enum_ProtocolType Type = Com_Enum_ProtocolType_None; if (!Com_Protocol_DecodeEnvelope(PacketBody, &Type, p_MessageBytes)) { return false; } return Type == ExpectedType; } bool Com_Protocol_DecodeHelloRspMessage( const QByteArray& MessageBytes, Com_Struct_ProtocolHelloRsp* p_Message) { *p_Message = Com_Struct_ProtocolHelloRsp(); int Offset = 0; while (Offset < MessageBytes.size()) { quint32 FieldNumber = 0; quint8 WireType = 0; quint64 Value = 0; if (!Com_Protocol_ReadKey(MessageBytes, &Offset, &FieldNumber, &WireType)) { return false; } switch (FieldNumber) { case 1: if ((WireType != kProtoWireVarint) || !Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value)) { return false; } p_Message->ProtocolVersion = static_cast(Value); break; case 2: if ((WireType != kProtoWireVarint) || !Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value)) { return false; } p_Message->VendorId = static_cast(Value); break; case 3: if ((WireType != kProtoWireVarint) || !Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value)) { return false; } p_Message->ProductId = static_cast(Value); break; case 4: if ((WireType != kProtoWireVarint) || !Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value)) { return false; } p_Message->FirmwareMajor = static_cast(Value); break; case 5: if ((WireType != kProtoWireVarint) || !Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value)) { return false; } p_Message->FirmwareMinor = static_cast(Value); break; case 6: if ((WireType != kProtoWireVarint) || !Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value)) { return false; } p_Message->CapabilityFlags = static_cast(Value); break; default: if (!Com_Protocol_SkipField(MessageBytes, &Offset, WireType)) { return false; } break; } } return true; } bool Com_Protocol_DecodeUsageBitmapMessage( const QByteArray& MessageBytes, QByteArray* p_UsageBitmap) { p_UsageBitmap->clear(); int Offset = 0; while (Offset < MessageBytes.size()) { quint32 FieldNumber = 0; quint8 WireType = 0; if (!Com_Protocol_ReadKey(MessageBytes, &Offset, &FieldNumber, &WireType)) { return false; } if (FieldNumber == 1) { if ((WireType != kProtoWireBytes) || !Com_Protocol_ReadLengthDelimited(MessageBytes, &Offset, p_UsageBitmap)) { return false; } return Com_Protocol_IsUsageBitmapValid(*p_UsageBitmap); } if (!Com_Protocol_SkipField(MessageBytes, &Offset, WireType)) { return false; } } return false; } bool Com_Protocol_DecodeFunctionKeyEventMessage( const QByteArray& MessageBytes, Com_Struct_ProtocolFunctionKeyEvent* p_Message) { *p_Message = Com_Struct_ProtocolFunctionKeyEvent(); bool HasBitmap = false; bool HasLegacyUsage = false; bool HasLegacyAction = false; int Offset = 0; while (Offset < MessageBytes.size()) { quint32 FieldNumber = 0; quint8 WireType = 0; quint64 Value = 0; if (!Com_Protocol_ReadKey(MessageBytes, &Offset, &FieldNumber, &WireType)) { return false; } switch (FieldNumber) { case 1: if (WireType == kProtoWireBytes) { if (!Com_Protocol_ReadLengthDelimited( MessageBytes, &Offset, &p_Message->UsageBitmap) || !Com_Protocol_IsUsageBitmapValid(p_Message->UsageBitmap)) { return false; } HasBitmap = true; break; } if ((WireType != kProtoWireVarint) || !Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value)) { return false; } if (Value > 0xFFFFU) { return false; } p_Message->Usage = static_cast(Value); HasLegacyUsage = true; break; case 2: if ((WireType != kProtoWireVarint) || !Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value)) { return false; } p_Message->Action = static_cast(Value); HasLegacyAction = true; break; default: if (!Com_Protocol_SkipField(MessageBytes, &Offset, WireType)) { return false; } break; } } p_Message->HasUsageAction = HasLegacyUsage && HasLegacyAction; return HasBitmap || p_Message->HasUsageAction; } bool Com_Protocol_DecodeLedStateMessage( const QByteArray& MessageBytes, Com_Struct_ProtocolLedState* p_Message) { *p_Message = Com_Struct_ProtocolLedState(); int Offset = 0; while (Offset < MessageBytes.size()) { quint32 FieldNumber = 0; quint8 WireType = 0; quint64 Value = 0; if (!Com_Protocol_ReadKey(MessageBytes, &Offset, &FieldNumber, &WireType)) { return false; } if (FieldNumber == 1) { if ((WireType != kProtoWireVarint) || !Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value)) { return false; } p_Message->LedMask = static_cast(Value); continue; } if (!Com_Protocol_SkipField(MessageBytes, &Offset, WireType)) { return false; } } return true; } bool Com_Protocol_DecodeAckMessage( const QByteArray& MessageBytes, Com_Struct_ProtocolAck* p_Message) { *p_Message = Com_Struct_ProtocolAck(); int Offset = 0; while (Offset < MessageBytes.size()) { quint32 FieldNumber = 0; quint8 WireType = 0; quint64 Value = 0; if (!Com_Protocol_ReadKey(MessageBytes, &Offset, &FieldNumber, &WireType)) { return false; } if (FieldNumber == 1) { if ((WireType != kProtoWireVarint) || !Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value)) { return false; } p_Message->AckedType = static_cast(Value); continue; } if (!Com_Protocol_SkipField(MessageBytes, &Offset, WireType)) { return false; } } return true; } bool Com_Protocol_DecodeErrorMessage( const QByteArray& MessageBytes, Com_Struct_ProtocolError* p_Message) { *p_Message = Com_Struct_ProtocolError(); int Offset = 0; while (Offset < MessageBytes.size()) { quint32 FieldNumber = 0; quint8 WireType = 0; quint64 Value = 0; if (!Com_Protocol_ReadKey(MessageBytes, &Offset, &FieldNumber, &WireType)) { return false; } switch (FieldNumber) { case 1: if ((WireType != kProtoWireVarint) || !Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value)) { return false; } p_Message->ErrorType = static_cast(Value); break; case 2: if ((WireType != kProtoWireVarint) || !Com_Protocol_ReadVarint(MessageBytes, &Offset, &Value)) { return false; } p_Message->ErrorCode = static_cast(Value); break; default: if (!Com_Protocol_SkipField(MessageBytes, &Offset, WireType)) { return false; } break; } } return true; } bool Com_Protocol_GetBitmapPosition(quint16 Usage, int* p_ByteIndex, quint8* p_BitMask) { if ((p_ByteIndex == nullptr) || (p_BitMask == nullptr)) { return false; } if ((Usage >= kUsageModifierFirst) && (Usage <= kUsageModifierLast)) { *p_ByteIndex = 0; *p_BitMask = static_cast(1U << (Usage - kUsageModifierFirst)); return true; } if (Usage <= kUsageNormalLast) { *p_ByteIndex = 1 + static_cast(Usage / 8U); *p_BitMask = static_cast(1U << (Usage % 8U)); return true; } return false; } } // namespace bool Com_Protocol_DecodeMessageType( const QByteArray& PacketBody, Com_Enum_ProtocolType* p_Type) { if (p_Type == nullptr) { return false; } QByteArray MessageBytes; return Com_Protocol_DecodeEnvelope(PacketBody, p_Type, &MessageBytes); } bool Com_Protocol_TryTakePacket( QByteArray* p_StreamBuffer, QByteArray* p_PacketBody, Com_Enum_ProtocolType* p_Type) { if ((p_StreamBuffer == nullptr) || (p_PacketBody == nullptr) || (p_Type == nullptr)) { return false; } p_PacketBody->clear(); *p_Type = Com_Enum_ProtocolType_None; if (p_StreamBuffer->isEmpty()) { return false; } int Offset = 0; quint32 FieldNumber = 0; quint8 WireType = 0; if (!Com_Protocol_ReadKey(*p_StreamBuffer, &Offset, &FieldNumber, &WireType)) { return false; } const Com_Enum_ProtocolType Type = Com_Protocol_TypeForFieldNumber(FieldNumber); if ((Type == Com_Enum_ProtocolType_None) || (WireType != kProtoWireBytes)) { return false; } QByteArray MessageBytes; if (!Com_Protocol_ReadLengthDelimited(*p_StreamBuffer, &Offset, &MessageBytes)) { return false; } *p_PacketBody = p_StreamBuffer->left(Offset); *p_Type = Type; p_StreamBuffer->remove(0, Offset); return true; } QByteArray Com_Protocol_EncodeHelloReq() { QByteArray MessageBytes; Com_Protocol_AppendUInt32Field(&MessageBytes, 1, 1); return Com_Protocol_EncodeEnvelope(Com_Enum_ProtocolType_HelloReq, MessageBytes); } QByteArray Com_Protocol_EncodeBitmap(const QByteArray& UsageBitmap) { if (!Com_Protocol_IsUsageBitmapValid(UsageBitmap)) { return QByteArray(); } QByteArray MessageBytes; Com_Protocol_AppendBytesField(&MessageBytes, 1, UsageBitmap); return Com_Protocol_EncodeEnvelope(Com_Enum_ProtocolType_Bitmap, MessageBytes); } QByteArray Com_Protocol_EncodeTimeSync( quint32 Version, quint32 Flags, qint32 TimezoneMinutes, quint64 UtcMilliseconds, quint32 AccuracyMilliseconds) { QByteArray MessageBytes; Com_Protocol_AppendUInt32Field(&MessageBytes, 1, Version); Com_Protocol_AppendUInt32Field(&MessageBytes, 2, Flags); Com_Protocol_AppendSInt32Field(&MessageBytes, 3, TimezoneMinutes); Com_Protocol_AppendFixed64Field(&MessageBytes, 4, UtcMilliseconds); Com_Protocol_AppendFixed32Field(&MessageBytes, 5, AccuracyMilliseconds); return Com_Protocol_EncodeEnvelope(Com_Enum_ProtocolType_TimeSync, MessageBytes); } QByteArray Com_Protocol_EncodeThemeRgb(quint8 Red, quint8 Green, quint8 Blue) { QByteArray MessageBytes; Com_Protocol_AppendUInt32Field(&MessageBytes, 1, Red); Com_Protocol_AppendUInt32Field(&MessageBytes, 2, Green); Com_Protocol_AppendUInt32Field(&MessageBytes, 3, Blue); return Com_Protocol_EncodeEnvelope(Com_Enum_ProtocolType_ThemeRgb, MessageBytes); } bool Com_Protocol_DecodeHelloRsp( const QByteArray& PacketBody, Com_Struct_ProtocolHelloRsp* p_Message) { Com_Enum_ProtocolType Type = Com_Enum_ProtocolType_None; QByteArray MessageBytes; if ((p_Message == nullptr) || !Com_Protocol_DecodeEnvelope(PacketBody, &Type, &MessageBytes) || (Type != Com_Enum_ProtocolType_HelloRsp)) { return false; } return Com_Protocol_DecodeHelloRspMessage(MessageBytes, p_Message); } bool Com_Protocol_DecodeFunctionKeyEvent( const QByteArray& PacketBody, Com_Struct_ProtocolFunctionKeyEvent* p_Message) { Com_Enum_ProtocolType Type = Com_Enum_ProtocolType_None; QByteArray MessageBytes; if ((p_Message == nullptr) || !Com_Protocol_DecodeEnvelope(PacketBody, &Type, &MessageBytes) || (Type != Com_Enum_ProtocolType_FunctionKeyEvent)) { return false; } return Com_Protocol_DecodeFunctionKeyEventMessage(MessageBytes, p_Message); } bool Com_Protocol_DecodeLedState( const QByteArray& PacketBody, Com_Struct_ProtocolLedState* p_Message) { Com_Enum_ProtocolType Type = Com_Enum_ProtocolType_None; QByteArray MessageBytes; if ((p_Message == nullptr) || !Com_Protocol_DecodeEnvelope(PacketBody, &Type, &MessageBytes) || (Type != Com_Enum_ProtocolType_LedState)) { return false; } return Com_Protocol_DecodeLedStateMessage(MessageBytes, p_Message); } bool Com_Protocol_DecodeAck( const QByteArray& PacketBody, Com_Struct_ProtocolAck* p_Message) { Com_Enum_ProtocolType Type = Com_Enum_ProtocolType_None; QByteArray MessageBytes; if ((p_Message == nullptr) || !Com_Protocol_DecodeEnvelope(PacketBody, &Type, &MessageBytes) || (Type != Com_Enum_ProtocolType_Ack)) { return false; } return Com_Protocol_DecodeAckMessage(MessageBytes, p_Message); } bool Com_Protocol_DecodeError( const QByteArray& PacketBody, Com_Struct_ProtocolError* p_Message) { Com_Enum_ProtocolType Type = Com_Enum_ProtocolType_None; QByteArray MessageBytes; if ((p_Message == nullptr) || !Com_Protocol_DecodeEnvelope(PacketBody, &Type, &MessageBytes) || (Type != Com_Enum_ProtocolType_Error)) { return false; } return Com_Protocol_DecodeErrorMessage(MessageBytes, p_Message); } bool Com_Protocol_DecodeAckForType( const QByteArray& PacketBody, Com_Enum_ProtocolType EnvelopeType, Com_Struct_ProtocolAck* p_Message) { QByteArray MessageBytes; if ((p_Message == nullptr) || (EnvelopeType != Com_Enum_ProtocolType_Ack) || !Com_Protocol_DecodeEnvelopeForExpectedType( PacketBody, Com_Enum_ProtocolType_Ack, &MessageBytes)) { return false; } return Com_Protocol_DecodeAckMessage(MessageBytes, p_Message); } bool Com_Protocol_DecodeErrorForType( const QByteArray& PacketBody, Com_Enum_ProtocolType EnvelopeType, Com_Struct_ProtocolError* p_Message) { QByteArray MessageBytes; if ((p_Message == nullptr) || (EnvelopeType != Com_Enum_ProtocolType_Error) || !Com_Protocol_DecodeEnvelopeForExpectedType( PacketBody, Com_Enum_ProtocolType_Error, &MessageBytes)) { return false; } return Com_Protocol_DecodeErrorMessage(MessageBytes, p_Message); } bool Com_Protocol_IsUsageBitmapValid(const QByteArray& UsageBitmap) { return UsageBitmap.size() == kUsageBitmapSize; } QByteArray Com_Protocol_CreateUsageBitmap() { return QByteArray(kUsageBitmapSize, 0); } bool Com_Protocol_TestUsageBitmapBit(const QByteArray& UsageBitmap, quint16 Usage) { int ByteIndex = 0; quint8 BitMask = 0; if (!Com_Protocol_IsUsageBitmapValid(UsageBitmap) || !Com_Protocol_GetBitmapPosition(Usage, &ByteIndex, &BitMask)) { return false; } return (static_cast(UsageBitmap.at(ByteIndex)) & BitMask) != 0U; } bool Com_Protocol_SetUsageBitmapBit(QByteArray* p_UsageBitmap, quint16 Usage, bool IsPressed) { int ByteIndex = 0; quint8 BitMask = 0; if ((p_UsageBitmap == nullptr) || !Com_Protocol_IsUsageBitmapValid(*p_UsageBitmap) || !Com_Protocol_GetBitmapPosition(Usage, &ByteIndex, &BitMask)) { return false; } quint8 ByteValue = static_cast(p_UsageBitmap->at(ByteIndex)); if (IsPressed) { ByteValue = static_cast(ByteValue | BitMask); } else { ByteValue = static_cast(ByteValue & ~BitMask); } (*p_UsageBitmap)[ByteIndex] = static_cast(ByteValue); return true; } QVector Com_Protocol_BuildPressedUsageList(const QByteArray& UsageBitmap) { QVector UsageList; if (!Com_Protocol_IsUsageBitmapValid(UsageBitmap)) { return UsageList; } for (quint16 Usage = 0; Usage <= kUsageNormalLast; ++Usage) { if (Com_Protocol_TestUsageBitmapBit(UsageBitmap, Usage)) { UsageList.append(Usage); } } for (quint16 Usage = kUsageModifierFirst; Usage <= kUsageModifierLast; ++Usage) { if (Com_Protocol_TestUsageBitmapBit(UsageBitmap, Usage)) { UsageList.append(Usage); } } return UsageList; }