/// <summary> /// Set the control to the given value by sending a state event with the value to the /// control's device. /// </summary> /// <param name="control">An input control on a device that has been added to the system.</param> /// <param name="state">New value for the input control.</param> /// <typeparam name="TValue">Value type of the given control.</typeparam> /// <example> /// <code> /// var gamepad = InputSystem.AddDevice<Gamepad>(); /// Set(gamepad.leftButton, 1); /// </code> /// </example> public void Set <TValue>(InputControl <TValue> control, TValue state, double absoluteTime = -1, double timeOffset = 0) where TValue : struct { if (control == null) { throw new ArgumentNullException(nameof(control)); } if (!control.device.added) { throw new ArgumentException( $"Device of control '{control}' has not been added to the system", nameof(control)); } using (StateEvent.From(control.device, out var eventPtr)) { ////REVIEW: should we by default take the time from the device here? if (absoluteTime >= 0) { eventPtr.time = absoluteTime; } eventPtr.time += timeOffset; control.WriteValueIntoEvent(state, eventPtr); InputSystem.QueueEvent(eventPtr); } InputSystem.Update(); }
/// <summary> /// Set the control to the given value by sending a state event with the value to the /// control's device. /// </summary> /// <param name="control">An input control on a device that has been added to the system.</param> /// <param name="state">New value for the input control.</param> /// <param name="time">Timestamp to use for the state event. If -1 (default), current time is used (see <see cref="InputTestFixture.currentTime"/>).</param> /// <param name="timeOffset">Offset to apply to the current time. This is an alternative to <paramref name="time"/>. By default, no offset is applied.</param> /// <param name="queueEventOnly">If true, no <see cref="InputSystem.Update"/> will be performed after queueing the event. This will only put /// the state event on the event queue and not do anything else. The default is to call <see cref="InputSystem.Update"/> after queuing the event. /// Note that not issuing an update means the state of the device will not change yet. This may affect subsequent Set/Press/Release/etc calls /// as they will not yet see the state change. /// /// Note that this parameter will be ignored if the test is a <c>[UnityTest]</c>. Multi-frame /// playmode tests will automatically process input as part of the Unity player loop.</param> /// <typeparam name="TValue">Value type of the given control.</typeparam> /// <example> /// <code> /// var gamepad = InputSystem.AddDevice<Gamepad>(); /// Set(gamepad.leftButton, 1); /// </code> /// </example> public void Set <TValue>(InputControl <TValue> control, TValue state, double time = -1, double timeOffset = 0, bool queueEventOnly = false) where TValue : struct { if (control == null) { throw new ArgumentNullException(nameof(control)); } if (!control.device.added) { throw new ArgumentException( $"Device of control '{control}' has not been added to the system", nameof(control)); } if (IsUnityTest()) { queueEventOnly = true; } void SetUpAndQueueEvent(InputEventPtr eventPtr) { ////REVIEW: should we by default take the time from the device here? if (time >= 0) { eventPtr.time = time; } eventPtr.time += timeOffset; control.WriteValueIntoEvent(state, eventPtr); InputSystem.QueueEvent(eventPtr); } // Touchscreen does not support delta events involving TouchState. if (control is TouchControl) { using (StateEvent.From(control.device, out var eventPtr)) SetUpAndQueueEvent(eventPtr); } else { // We use delta state events rather than full state events here to mitigate the following problem: // Grabbing state from the device will preserve the current values of controls covered in the state. // However, running an update may alter the value of one or more of those controls. So with a full // state event, we may be writing outdated data back into the device. For example, in the case of delta // controls which will reset in OnBeforeUpdate(). // // Using delta events, we may still grab state outside of just the one control in case we're looking at // bit-addressed controls but at least we can avoid the problem for the majority of controls. using (DeltaStateEvent.From(control, out var eventPtr)) SetUpAndQueueEvent(eventPtr); } if (!queueEventOnly) { InputSystem.Update(); } }
protected static unsafe void Accumulate(InputControl <float> control, void *oldStatePtr, InputEventPtr newState) { if (control == null) { throw new ArgumentNullException(nameof(control)); } if (!control.ReadUnprocessedValueFromEvent(newState, out var newDelta)) { return; // Value for the control not contained in the given event. } var oldDelta = control.ReadUnprocessedValueFromState(oldStatePtr); control.WriteValueIntoEvent(oldDelta + newDelta, newState); }
/// <summary> /// Queue a value change on the given <paramref name="control"/> which will be processed and take effect /// in the next input update. /// </summary> /// <param name="control">Control to change the value of.</param> /// <param name="value">New value for the control.</param> /// <param name="time">Optional time at which the value change should take effect. If set, this will become /// the <see cref="InputEvent.time"/> of the queued event. If the time is in the future, the event will not /// be processed until it falls within the time of an input update slice (except if <see cref="InputSettings.timesliceEvents"/> /// is false, in which case the event will invariably be consumed in the next update).</param> /// <typeparam name="TValue">Type of value.</typeparam> /// <exception cref="ArgumentNullException"><paramref name="control"/> is null.</exception> public static void QueueValueChange <TValue>(this InputControl <TValue> control, TValue value, double time = -1) where TValue : struct { if (control == null) { throw new ArgumentNullException(nameof(control)); } ////TODO: if it's not a bit-addressing control, send a delta state change only using (StateEvent.From(control.device, out var eventPtr)) { if (time >= 0) { eventPtr.time = time; } control.WriteValueIntoEvent(value, eventPtr); InputSystem.QueueEvent(eventPtr); } }