/// <summary>
        /// This method updates the state of a contact.
        /// </summary>
        /// <param name="id">The contactId in the RDPINPUT_CONTACT_DATA.</param>
        /// <param name="contactFlag">The valid value of contactFlags in the RDPINPUT_CONTACT_DATA</param>
        /// <param name="x">The x value of the previous position of the contact.</param>
        /// <param name="y">The y value of the previous position of the contact.</param>
        /// <returns>Returns 0 if the update succeeds. Returns 1 if the contact state transition is invalid. Returns 2 if the contact position changes when transitioning from "engaged" state to "out of range" or "hovering" state, which is unexpected.</returns>
        public byte UpdateContactsMap(byte id, ValidStateFlagCombinations contactFlag, int x, int y)
        {
            if (!contactStateMap.ContainsKey(id))
            {
                contactStateMap.Add(id, new TouchContactAttribute(TouchContactState.OutOfRange, -1, -1));
            }
            TouchContactAttribute attr;

            contactStateMap.TryGetValue(id, out attr);
            TouchContactState s;
            bool fResult = transitionDiagram.TryGetValue(new StateFlags(attr.state, contactFlag), out s);

            // Invalid contact state transition
            if (!fResult)
            {
                return(1);
            }
            // Check whether the contact position changes when transitioning from "engaged" state to "out of range" or "hovering" state.
            if (contactFlag == ValidStateFlagCombinations.UP || contactFlag == ValidStateFlagCombinations.UP_CANCELED || contactFlag == ValidStateFlagCombinations.UP_INRANGE)
            {
                TouchContactAttribute attribute;
                contactStateMap.TryGetValue(id, out attribute);
                if (x != attribute.x || y != attribute.y)
                {
                    return(2);
                }
            }
            // Valid contact state transition, update the contact state.
            contactStateMap.Remove(id);
            contactStateMap.Add(id, new TouchContactAttribute(s, x, y));
            return(0);
        }
        private void InsertStateFlagTransition(TouchContactState srcState, ValidStateFlagCombinations flag, TouchContactState desState)
        {
            StateFlags sf = new StateFlags {
                state = srcState, flag = flag
            };

            transitionDiagram.Add(sf, desState);
        }
        /// <summary>
        /// This method is used to verify the structure of RDPINPUT_TOUCH_EVENT_PDU or RDPINPUT_DISMISS_HOVERING_CONTACT_PDU, and update the contact transition state according to the contacts contained in the message.
        /// </summary>
        /// <param name="inputPdu">The input pdu.</param>
        /// <param name="isFirstFrame">Whether the input pdu is the first pdu that client has transmitted.</param>
        public void VerifyAndUpdateContactState(RDPINPUT_PDU inputPdu, bool isFirstFrame)
        {
            if (inputPdu == null)
            {
                return;
            }
            if (inputPdu is RDPINPUT_TOUCH_EVENT_PDU)
            {
                RDPINPUT_TOUCH_EVENT_PDU pdu = inputPdu as RDPINPUT_TOUCH_EVENT_PDU;
                Site.Assert.IsNotNull(pdu.header, "The header of RDPINPUT_TOUCH_EVENT_PDU should not be null.");
                Site.Assert.IsNotNull(pdu.frames, "The array of RDPINPUT_TOUCH_FRAME in RDPINPUT_TOUCH_EVENT_PDU should not be null.");
                Site.Assert.AreEqual(pdu.header.pduLength, pdu.Length(), "The length of the RDPINPUT_TOUCH_EVENT_PDU message is expected to be the same with the pduLength in header.");
                Site.Assert.AreEqual((int)pdu.frameCount.ToUShort(), pdu.frames.Length, "The size of the array frames in RDPINPUT_TOUCH_EVENT_PDU is expected to be the same with the frameCount .");
                if (isFirstFrame)
                {
                    Site.Assert.IsTrue(pdu.frames[0].frameOffset.ToULong() == 0, "The field frameOffset of the first frame being transmitted must be set to zero.");
                }
                foreach (RDPINPUT_TOUCH_FRAME f in pdu.frames)
                {
                    Site.Assert.AreEqual((int)f.contactCount.ToUShort(), f.contacts.Length, "The size of the array contacts in RDPINPUT_TOUCH_FRAME is expected to be the same with the contactCount .");
                    foreach (RDPINPUT_CONTACT_DATA d in f.contacts)
                    {
                        if (((RDPINPUT_CONTACT_DATA_FieldsPresent)(d.fieldsPresent.ToUShort())).HasFlag(RDPINPUT_CONTACT_DATA_FieldsPresent.CONTACT_DATA_CONTACTRECT_PRESENT))
                        {
                            Site.Assert.IsNotNull(d.contactRectBottom, "The contactRectBottom is not expected to be null when flag CONTACT_DATA_CONTACTRECT_PRESENT in filedsPresent is set.");
                            Site.Assert.IsNotNull(d.contactRectTop, "The contactRectTop is not expected to be null when flag CONTACT_DATA_CONTACTRECT_PRESENT in filedsPresent is set.");
                            Site.Assert.IsNotNull(d.contactRectLeft, "The contactRectLeft is not expected to be null when flag CONTACT_DATA_CONTACTRECT_PRESENT in filedsPresent is set.");
                            Site.Assert.IsNotNull(d.contactRectRight, "The contactRectRight is not expected to be null when flag CONTACT_DATA_CONTACTRECT_PRESENT in filedsPresent is set.");
                        }
                        if (((RDPINPUT_CONTACT_DATA_FieldsPresent)(d.fieldsPresent.ToUShort())).HasFlag(RDPINPUT_CONTACT_DATA_FieldsPresent.CONTACT_DATA_ORIENTATION_PRESENT))
                        {
                            Site.Assert.IsNotNull(d.orientation, "The orientation is not expected to be null when flag CONTACT_DATA_ORIENTATION_PRESENT in filedsPresent is set.");
                        }
                        if (((RDPINPUT_CONTACT_DATA_FieldsPresent)(d.fieldsPresent.ToUShort())).HasFlag(RDPINPUT_CONTACT_DATA_FieldsPresent.CONTACT_DATA_PRESSURE_PRESENT))
                        {
                            Site.Assert.IsNotNull(d.pressure, "The orientation is not expected to be null when flag CONTACT_DATA_PRESSURE_PRESENT in filedsPresent is set.");
                        }

                        Site.Assert.IsTrue(Enum.IsDefined(typeof(ValidStateFlagCombinations), d.contactFlags.ToUInt()), "The value of contactFlags does not contain a valid combination of the contact state flags.");
                        ValidStateFlagCombinations temp = (ValidStateFlagCombinations)(d.contactFlags.ToUInt());
                        byte result = stateMachine.UpdateContactsMap(d.contactId, temp, d.x.ToInt(), d.y.ToInt());

                        Site.Assert.AreNotEqual(result, 1, "The contact state transition is invalid.");
                        Site.Assert.AreNotEqual(result, 2, "The contact position cannot change when transitioning from 'engaged' state to 'hovering' or 'out of range' state.");
                    }
                }
            }
            else if (inputPdu is RDPINPUT_DISMISS_HOVERING_CONTACT_PDU)
            {
                RDPINPUT_DISMISS_HOVERING_CONTACT_PDU pdu = inputPdu as RDPINPUT_DISMISS_HOVERING_CONTACT_PDU;
                Site.Assert.IsNotNull(pdu.header, "The header of RDPINPUT_DISMISS_HOVERING_CONTACT_PDU should not be null.");
                Site.Assert.AreEqual(pdu.header.eventId, EventId_Values.EVENTID_DISMISS_HOVERING_CONTACT, "The eventId in the header of RDPINPUT_DISMISS_HOVERING_CONTACT_PDU is expected to be EVENTID_DISMISS_HOVERING_CONTACT.");
                Site.Assert.AreEqual(pdu.header.pduLength, pdu.Length(), "The length of the RDPINPUT_DISMISS_HOVERING_CONTACT_PDU message is expected to be the same with the pduLength in header.");
                TouchContactAttribute attr;
                if (stateMachine.contactStateMap.TryGetValue(pdu.contactId, out attr))
                {
                    Site.Assert.AreEqual(attr.state, TouchContactState.Hovering, "The contact {0} is expected to be in hovering state.", pdu.contactId);
                    stateMachine.UpdateContactsMap(pdu.contactId, ValidStateFlagCombinations.UPDATE, 0, 0);
                }
                else
                {
                    Site.Assert.IsTrue(false, "The contact {0} is expected to be in hovering state, but it's out of range.", pdu.contactId);
                }
            }
            else
            {
                Site.Assert.IsTrue(false, "Unexpected message.");
            }
        }
 public StateFlags(TouchContactState s, ValidStateFlagCombinations f)
 {
     state = s;
     flag  = f;
 }
 private void InsertStateFlagTransition(TouchContactState srcState, ValidStateFlagCombinations flag, TouchContactState desState)
 {
     StateFlags sf = new StateFlags { state = srcState, flag = flag };
     transitionDiagram.Add(sf, desState);
 }
 /// <summary>
 /// This method updates the state of a contact.
 /// </summary>
 /// <param name="id">The contactId in the RDPINPUT_CONTACT_DATA.</param>
 /// <param name="contactFlag">The valid value of contactFlags in the RDPINPUT_CONTACT_DATA</param>
 /// <param name="x">The x value of the previous position of the contact.</param>
 /// <param name="y">The y value of the previous position of the contact.</param>
 /// <returns>Returns 0 if the update succeeds. Returns 1 if the contact state transition is invalid. Returns 2 if the contact position changes when transitioning from "engaged" state to "out of range" or "hovering" state, which is unexpected.</returns>
 public byte UpdateContactsMap(byte id, ValidStateFlagCombinations contactFlag, int x, int y)
 {
     if (!contactStateMap.ContainsKey(id))
     {
         contactStateMap.Add(id, new TouchContactAttribute(TouchContactState.OutOfRange, -1, -1));
     }
     TouchContactAttribute attr;
     contactStateMap.TryGetValue(id, out attr);
     TouchContactState s;
     bool fResult = transitionDiagram.TryGetValue(new StateFlags(attr.state, contactFlag), out s);
     // Invalid contact state transition
     if (!fResult)
     {
         return 1;
     }
     // Check whether the contact position changes when transitioning from "engaged" state to "out of range" or "hovering" state.
     if (contactFlag == ValidStateFlagCombinations.UP || contactFlag == ValidStateFlagCombinations.UP_CANCELED || contactFlag == ValidStateFlagCombinations.UP_INRANGE)
     {
         TouchContactAttribute attribute;
         contactStateMap.TryGetValue(id, out attribute);
         if (x != attribute.x || y != attribute.y)
         {
             return 2;
         }
     }
     // Valid contact state transition, update the contact state.
     contactStateMap.Remove(id);
     contactStateMap.Add(id, new TouchContactAttribute(s, x, y));
     return 0;
 }
 public StateFlags(TouchContactState s, ValidStateFlagCombinations f)
 {
     state = s;
     flag = f;
 }