The slow-path Input Event PDU is used to transmit input events from client to server.
file:///C:/ts_dev/TestSuites/MS-RDPBCGR/TestSuite/Src/TD/latest_XMLS_16may/RDPBCGR/ _rfc_ms-rdpbcgr2_1_7_1_1_3.xml
Inheritance: RdpbcgrClientPdu
        /// <summary>
        /// Decode Slow-Path Update PDU including Slow-Path Graphics Update PDU and Slow-Path Pointer Update PDU.
        /// </summary>
        /// <param name="data">data to be parsed</param>
        /// <param name="decryptedUserData">decrypted user data to be parsed</param>
        /// <param name="type">security header type</param>
        /// <returns>decoded Slow-Path Update PDU</returns>
        public StackPacket DecodeSlowPathInputEventPDU(
            byte[] data,
            byte[] decryptedUserData,
            SecurityHeaderType type)
        {
            TS_INPUT_PDU pdu = new TS_INPUT_PDU();

            // data index
            int dataIndex = 0;

            // SlowPathOutputPDU: commonHeader
            pdu.commonHeader = ParseMcsCommonHeader(data, ref dataIndex, type);

            // user data index
            int userDataIndex = 0;

            // SlowPathOutputPDU: slowPathUpdates
            pdu.shareDataHeader = ParseTsShareDataHeader(decryptedUserData, ref userDataIndex);

            pdu.numberEvents = ParseUInt16(decryptedUserData, ref userDataIndex, false);
            pdu.pad2Octets = ParseUInt16(decryptedUserData, ref userDataIndex, false);
            pdu.slowPathInputEvents = new Collection<TS_INPUT_EVENT>();

            // ETW Provider Dump Message
            if (pdu.commonHeader.securityHeader != null)
            {
                // RDP Standard Security
                string messageName = "RDPBCGR:" + pdu.GetType().Name;
                ExtendedLogger.DumpMessage(messageName, RdpbcgrUtility.DumpLevel_Layer3, pdu.GetType().Name, decryptedUserData);
            }

            while (userDataIndex < decryptedUserData.Length)
            {
                pdu.slowPathInputEvents.Add(ParseSlowPathInputEvent(decryptedUserData, ref userDataIndex));
            }

            // Check if data length exceeded expectation
            VerifyDataLength(decryptedUserData.Length, userDataIndex, ConstValue.ERROR_MESSAGE_DATA_LENGTH_EXCEEDED);
            return pdu;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="inputPdu"></param>
        public void VerifyPdu(TS_INPUT_PDU inputPdu)
        {
            int versionLow = inputPdu.shareDataHeader.shareControlHeader.pduType.typeAndVersionLow>>4&0x0F;
            site.CaptureRequirementIfAreEqual<int>(1, versionLow, 1542,
                @"In TS_SHARECONTROLHEADER structure, for PduType's subfield, versionLow field MUST be set to TS_PROTOCOL_VERSION (0x1).");
            // not capture 1543
            //CaptureRequirement(inputPdu.shareDataHeader.shareControlHeader.pduType.versionHigh == 0, 1543);
            site.CaptureRequirementIfAreEqual<versionHigh_Values>(versionHigh_Values.V1, inputPdu.shareDataHeader.shareControlHeader.pduType.versionHigh, 1544,
                @"In TS_SHARECONTROLHEADER, for PduType's subfield, the versionHigh field must be 1 byte which is the most "
                + @"significant byte of pduType field.");

            site.CaptureRequirementIfIsTrue(inputPdu.shareDataHeader.streamId == streamId_Values.STREAM_UNDEFINED ||
                inputPdu.shareDataHeader.streamId == streamId_Values.STREAM_LOW ||
                inputPdu.shareDataHeader.streamId == streamId_Values.STREAM_MED ||
                inputPdu.shareDataHeader.streamId == streamId_Values.STREAM_HI,
                1554,
                @"In TS_SHAREDATAHEADER structure,  the streamId can be the following: STREAM_UNDEFINED 0x00 ,STREAM_LOW"
                + @" 0x01,STREAM_MED 0x02,STREAM_HI 0x04");

            //R1612 cannot be verified
            if( inputPdu.commonHeader.securityHeader != null && (inputPdu.commonHeader.securityHeader.flags & TS_SECURITY_HEADER_flags_Values.SEC_FLAGSHI_VALID ) == TS_SECURITY_HEADER_flags_Values.SEC_FLAGSHI_VALID )
                CaptureRequirement(inputPdu.commonHeader.securityHeader.flagsHi != 0, 1611);

            if (inputPdu.commonHeader.securityHeader is TS_SECURITY_HEADER2)
            {
                TS_SECURITY_HEADER2 header2 = (TS_SECURITY_HEADER2)inputPdu.commonHeader.securityHeader;
                site.CaptureRequirementIfAreEqual<TS_SECURITY_HEADER2_length_Values>(TS_SECURITY_HEADER2_length_Values.V1, header2.length,  1619,
                    @"The TS_SECURITY_HEADER2 structure,the length field MUST be set to 0x0010 (16 bytes) for legacy reasons.");
                //have defined ConstValue.TSFIPS_VERSION1 in sdk
                site.CaptureRequirementIfAreEqual<byte>(1, header2.version, 1621,
                    @"In TS_SECURITY_HEADER2 structure,the version field SHOULD be set to TSFIPS_VERSION1 (0x01).");
            }

            //2.2.8.1.1.3
            if (serverConfig.encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_40BIT ||
                serverConfig.encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_56BIT ||
                serverConfig.encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_128BIT)
            {
                site.CaptureRequirementIfIsInstanceOfType(inputPdu.commonHeader.securityHeader, typeof(TS_SECURITY_HEADER1), 1630,
                    @"In Client Input Event PDU (TS_INPUT_PDU), If Standard RDP Security is in effect and the "
                    + @"Encryption Method selected by the server is greater than ENCRYPTION_METHOD_NONE (0),"
                    + @" then this securityHeader field will contain Non-FIPS Security Header (section 2.2.8.1.1.2.2)"
                    + @" if the Encryption Level Method selected by the server (see sections 5.3.2 and 2.2.1.4.3)"
                    + @" is ENCRYPTION_LEVEL_LOW (1METHOD_40BIT (0x00000001), ENCRYPTION_LEVEL_CLIENT_COMPATIBLE"
                    + @" (2METHOD_56BIT (0x00000008), or ENCRYPTION_LEVEL_HIGH (3). METHOD_128BIT (0x00000002).");
            }
            else if (serverConfig.encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_FIPS)
            {
                site.CaptureRequirementIfIsInstanceOfType(inputPdu.commonHeader.securityHeader, typeof(TS_SECURITY_HEADER2), 1631,
                    @"In Client Input Event PDU (TS_INPUT_PDU),If Standard RDP Security is in effect and the "
                    + @"Encryption Method selected by the server is greater than ENCRYPTION_METHOD_NONE (0),"
                    + @" then this securityHeader field will contain FIPS Security Header (section 2.2.8.1.1.2.3)"
                    + @" if the Encryption LevelMethod selected by the server (see sections 5.3.2 and 2.2.1.4.3) "
                    + @"is ENCRYPTION_METHOD_FIPS (0x00000010). ");
            }
            else if (serverConfig.encryptionMethod == EncryptionMethods.ENCRYPTION_METHOD_NONE)
            {
                site.CaptureRequirementIfIsNull(inputPdu.commonHeader.securityHeader, 1632,
                    @"In Client Input Event PDU (TS_INPUT_PDU),If Enhanced RDP Security is in effect or the "
                    + @"Encryption Method selected by the server  is ENCRYPTION_METHOD_NONE (0), then this "
                    + @"securityHeader field MUST NOT be included in the PDU.");
            }

            //2.2.8.1.1.3.1
            site.CaptureRequirementIfAreEqual<ShareControlHeaderType>(ShareControlHeaderType.PDUTYPE_DATAPDU, (ShareControlHeaderType)(inputPdu.shareDataHeader.shareControlHeader.pduType.typeAndVersionLow & 0x0F), 1635,
                @"In Client Input Event PDU (TS_INPUT_PDU),the shareDataHeader field contains information about"
                + @" the packet. The type subfield of the pduType field of the Share Control Header MUST be set"
                + @" to PDUTYPE_DATAPDU (7). ");
            site.CaptureRequirementIfAreEqual<pduType2_Values>(pduType2_Values.PDUTYPE2_INPUT, inputPdu.shareDataHeader.pduType2, 1636,
                @"In Client Input Event PDU (TS_INPUT_PDU),the pduType2 field of the Share Data Header MUST be "
                + @"set to PDUTYPE2_INPUT (28).");

            //2.2.8.1.1.3.1.1
            foreach (TS_INPUT_EVENT e in inputPdu.slowPathInputEvents)
            {
                VerifyStructure(e);
            }
        }
 /// <summary>
 /// Create an instance of the class that is identical to the current PDU. 
 /// </summary>
 /// <returns>The new instance.</returns>
 public override StackPacket Clone()
 {
     TS_INPUT_PDU cloneInputPdu = new TS_INPUT_PDU(context);
     cloneInputPdu.commonHeader = commonHeader.Clone();
     cloneInputPdu.numberEvents = numberEvents;
     cloneInputPdu.pad2Octets = pad2Octets;
     cloneInputPdu.shareDataHeader = shareDataHeader;
     if (slowPathInputEvents != null)
     {
         cloneInputPdu.slowPathInputEvents = new Collection<TS_INPUT_EVENT>();
         for (int count = 0; count < this.slowPathInputEvents.Count; count++)
         {
             cloneInputPdu.slowPathInputEvents.Add(slowPathInputEvents[count]);
         }
     }
     return cloneInputPdu;
 }