/// <summary> /// Remove an active user. /// </summary> /// <param name="user">An active user.</param> /// <exception cref="ArgumentNullException"><paramref name="user"/> is <c>null</c>.</exception> /// <remarks> /// Removing a user also unassigns all currently assigned devices from the user. On completion of this /// method, <see cref="devices"/> of <paramref name="user"/> will be empty. /// </remarks> public static void Remove(IInputUser user) { if (user == null) { throw new ArgumentNullException("user"); } var index = FindUserIndex(user); if (index == -1) { return; } // Remove devices. var userData = s_AllUserData[index]; if (userData.deviceCount > 0) { ArrayHelpers.EraseSliceWithCapacity(ref s_AllDevices, ref s_AllDeviceCount, userData.deviceStartIndex, userData.deviceCount); } // Remove. var userCount = s_AllUserCount; ArrayHelpers.EraseAtWithCapacity(ref s_AllUsers, ref userCount, index); ArrayHelpers.EraseAtWithCapacity(ref s_AllUserData, ref s_AllUserCount, index); // Send notification. Notify(user, InputUserChange.Removed); }
private static void Notify(IInputUser user, InputUserChange change) { for (var i = 0; i < s_OnChange.length; ++i) { s_OnChange[i](user, change); } }
public static void AssignInputDevices <TDevices>(this IInputUser user, TDevices devices) where TDevices : IEnumerable <InputDevice> // Parameter so that compiler can know enumerable type instead of having to go through the interface. { if (devices == null) { throw new ArgumentNullException("devices"); } var userIndex = FindUserIndex(user); if (userIndex == -1) { throw new InvalidOperationException(string.Format("User '{0}' has not been added to the system", user)); } var wasAdded = false; foreach (var device in devices) { if (device == null) { continue; } wasAdded |= AssignDeviceInternal(userIndex, device); } if (wasAdded) { Notify(user, InputUserChange.DevicesChanged); } }
/// <summary> /// Called when an action is triggered from a device that isn't assigned to any user. /// </summary> /// <param name="user"></param> /// <param name="action"></param> /// <param name="control"></param> /// <remarks> /// In single-player mode, we concurrently enable all our bindings from all available control schemes. /// This means that the actions will bind to whatever devices are available. However, we only assign /// the devices actively used with the current control scheme to the user. This means that we always know /// how the player is currently controlling the game. /// /// When the player uses a binding that isn't part of the current control scheme, this method will /// be called. In here we automatically switch control schemes by looking at which control scheme is /// suited to the unassigned device. /// /// Note that the logic here also covers the case where there are multiple devices meant to be used /// with the same control scheme. For example, there may be two gamepads and the player is free to /// switch from one or the other. In that case, while we will stay on the Gamepad control scheme, /// we will still unassign the previously used gamepad from the player and assign the newly used one. /// </remarks> private void OnUnassignedDeviceUsed(IInputUser user, InputAction action, InputControl control) { // We only support control scheme switching in single player. if (!m_SinglePlayer) { return; } // All our IInputUsers are expected to be DemoPlayerControllers. var player = user as DemoPlayerController; if (player == null) { return; } ////REVIEW: should we just look at the binding that triggered and go by the binding group it is in? // Select a control scheme based on the device that was used. var device = control.device; var controlScheme = player.SelectControlSchemeBasedOnDevice(device); // Give the device to the user and then switch control schemes. // If the control scheme requires additional devices, we select them automatically using // AndAssignMissingDevices(). user.ClearAssignedInputDevices(); user.AssignInputDevice(device); user.AssignControlScheme(controlScheme) .AndAssignMissingDevices(); }
/// <summary> /// Get the sequence number of the user. /// </summary> /// <remarks> /// It can be useful to establish a sorting of players locally such that it is /// known who is the first player, who is the second, and so on. This property /// gives the positioning of the user within the globally established sequence. /// /// Note that the index of a user may change as users are added and removed. /// </remarks> public static int GetUserIndex(this IInputUser user) { if (user == null) { throw new ArgumentNullException("user"); } return(FindUserIndex(user)); }
/// <inheritdoc /> public async Task <TUserFull> GetUserFullAsync(IInputUser inputUser, CancellationToken cancellationToken = default(CancellationToken)) { var request = new RequestGetFullUser { Id = inputUser }; return((TUserFull)await RequestSender.SendRequestAsync(request, cancellationToken).ConfigureAwait(false)); }
/// <inheritdoc /> public async Task <TLink> DeleteContactAsync(IInputUser user, CancellationToken cancellationToken = default(CancellationToken)) { ClientSettings.EnsureUserAuthorized(); var req = new RequestDeleteContact { Id = user }; return((TLink)await RequestSender.SendRequestAsync(req, cancellationToken).ConfigureAwait(false)); }
private static int FindUserIndex(IInputUser user) { for (var i = 0; i < s_AllUserCount; ++i) { if (s_AllUsers[i] == user) { return(i); } } return(-1); }
/// <summary> /// Deletes a user from a chat and sends a service message on it. /// </summary> /// <param name="chatId">Chat's identifier</param> /// <param name="user">User ID to be deleted</param> /// <returns> /// Returns a <see cref="IUpdates"/> object containing a service message sent during the action. /// </returns> public async Task <IUpdates> DeleteChatUser(int chatId, IInputUser user) { EnsureUserAuthorized(); var request = new RequestDeleteChatUser { ChatId = chatId, UserId = user }; return(await SenderService.SendRequestAsync(request).ConfigureAwait(false)); }
/// <inheritdoc /> public async Task <IUpdates> DeleteChatUser(int chatId, IInputUser user, CancellationToken cancellationToken = default(CancellationToken)) { ClientSettings.EnsureUserAuthorized(); var request = new RequestDeleteChatUser { ChatId = chatId, UserId = user }; return(await RequestSender.SendRequestAsync(request, cancellationToken).ConfigureAwait(false)); }
/// <inheritdoc /> public async Task <IPhotos> GetUserPhotosAsync(IInputUser user, int offset = 0, int limit = 200, long maxId = 0, CancellationToken cancellationToken = default(CancellationToken)) { var request = new RequestGetUserPhotos { UserId = user, MaxId = maxId, Limit = limit, Offset = offset }; return(await RequestSender.SendRequestAsync(request, cancellationToken).ConfigureAwait(false)); }
/// <summary> /// Adds a user to a chat and sends a service message on it. /// </summary> /// <param name="chatId">Chat's identifier</param> /// <param name="user">User ID to be added</param> /// <param name="limit">Number of last messages to be forwarded</param> /// <returns> /// Returns a <see cref="IUpdates"/> object contains info on one message with auxiliary data and data on the current state of updates. /// </returns> public async Task <IUpdates> AddChatUserAsync(int chatId, IInputUser user, int limit) { EnsureUserAuthorized(); var request = new RequestAddChatUser { ChatId = chatId, UserId = user, FwdLimit = limit }; return(await SenderService.SendRequestAsync(request).ConfigureAwait(false)); }
/// <summary>Adds a user to a chat and sends a service message on it.</summary> /// <param name="chatId">Chat's identifier</param> /// <param name="user">User ID to be added</param> /// <param name="limit">Number of last messages to be forwarded</param> /// <returns> /// Returns a <see cref="IUpdates" /> object contains info on one message with auxiliary data and data on the /// current state of updates. /// </returns> public async Task <IUpdates> AddChatUserAsync(int chatId, IInputUser user, int limit, CancellationToken cancellationToken = default(CancellationToken)) { AuthApiService.EnsureUserAuthorized(); var request = new RequestAddChatUser { ChatId = chatId, UserId = user, FwdLimit = limit }; return(await SenderService.SendRequestAsync(request, cancellationToken).ConfigureAwait(false)); }
/// <summary> /// Get the unique numeric ID of the user. /// </summary> /// <remarks> /// The ID of a user cannot be changed over its lifetime. Also, while the user /// is active, no other player can have the same ID. /// </remarks> public static ulong GetUserId(this IInputUser user) { if (user == null) { throw new ArgumentNullException("user"); } var index = FindUserIndex(user); if (index == -1) { return(kInvalidId); } return(s_AllUserData[index].id); }
/// <summary> /// Get the control scheme currently employed by the user. /// </summary> /// <remarks> /// /// Note that if bindings are enabled that are not part of the active control scheme, /// this property will automatically change value according to what bindings are being /// used. /// /// Any time the value of this property change (whether by <see cref="SetControlScheme"/> /// or by automatic switching), a notification is sent on <see cref="onChange"/> with /// <see cref="InputUserChange.ControlSchemeChanged"/>. /// </remarks> public static InputControlScheme?GetControlScheme(this IInputUser user) { if (user == null) { throw new ArgumentNullException("user"); } var index = FindUserIndex(user); if (index == -1) { return(null); } return(s_AllUserData[index].controlScheme); }
/// <summary> /// Get the list of <see cref="InputDevice">input devices</see> assigned to the user. /// </summary> /// <remarks> /// Devices do not necessarily need to be unique to a user. For example, two users may both /// be assigned the same keyboard in a split-screen game where one user uses the left side and /// another user uses the right side of the keyboard. Another example is a game where players /// take turns on the same machine. /// </remarks> public static ReadOnlyArray <InputDevice> GetAssignedInputDevices(this IInputUser user) { if (user == null) { throw new ArgumentNullException("user"); } var index = FindUserIndex(user); if (index == -1) { return(new ReadOnlyArray <InputDevice>()); } return(new ReadOnlyArray <InputDevice>(s_AllDevices, s_AllUserData[index].deviceStartIndex, s_AllUserData[index].deviceCount)); }
/// <summary> /// Add a new user. /// </summary> /// <param name="userName">Optional <see cref="userName"/> to assign to the newly created user.</param> /// <returns>A newly created user.</returns> /// <remarks> /// Adding a user sends a notification with <see cref="InputUserChange.Added"/> through <see cref="onChange"/>. /// /// The user will start out with no devices and no actions assigned. /// /// The user is added to <see cref="all"/>. /// </remarks> public static void Add(IInputUser user, string userName = null) { if (user == null) { throw new ArgumentNullException("user"); } var userData = new UserData { id = ++s_LastUserId, userName = userName, }; // Add to list. var userCount = s_AllUserCount; ArrayHelpers.AppendWithCapacity(ref s_AllUsers, ref userCount, user); ArrayHelpers.AppendWithCapacity(ref s_AllUserData, ref s_AllUserCount, userData); // Send notification. Notify(user, InputUserChange.Added); }
public static void SetUserName(this IInputUser user, string userName) { if (user == null) { throw new ArgumentNullException("user"); } var index = FindUserIndex(user); if (index == -1) { throw new InvalidOperationException(string.Format("User '{0}' has not been added to the system", user)); } if (string.Compare(s_AllUserData[index].userName, userName) == 0) { return; } s_AllUserData[index].userName = userName; Notify(user, InputUserChange.NameChanged); }
public static void AssignInputDevice(this IInputUser user, InputDevice device) { if (user == null) { throw new ArgumentNullException("user"); } if (device == null) { throw new ArgumentNullException("device"); } var userIndex = FindUserIndex(user); if (userIndex == -1) { throw new InvalidOperationException(string.Format("User '{0}' has not been added to the system", user)); } if (AssignDeviceInternal(userIndex, device)) { Notify(user, InputUserChange.DevicesChanged); } }
public static void SetControlScheme(this IInputUser user, string schemeName) { if (user == null) { throw new ArgumentNullException("user"); } var index = FindUserIndex(user); if (index == -1) { throw new InvalidOperationException(string.Format("User '{0}' has not been added to the system", user)); } if (string.IsNullOrEmpty(schemeName) && !s_AllUserData[index].controlScheme.HasValue) { return; } if (!string.IsNullOrEmpty(schemeName) && s_AllUserData[index].controlScheme.HasValue && string.Compare( s_AllUserData[index].controlScheme.Value.m_Name, schemeName, StringComparison.InvariantCultureIgnoreCase) == 0) { return; } if (string.IsNullOrEmpty(schemeName)) { s_AllUserData[index].controlScheme = null; } else { s_AllUserData[index].controlScheme = new InputControlScheme(schemeName); } Notify(user, InputUserChange.ControlSchemeChanged); }
public static void SetControlScheme(this IInputUser user, InputControlScheme scheme) { if (user == null) { throw new ArgumentNullException("user"); } var index = FindUserIndex(user); if (index == -1) { throw new InvalidOperationException(string.Format("User '{0}' has not been added to the system", user)); } // Ignore if the control scheme is already set on the user. if (s_AllUserData[index].controlScheme.HasValue && s_AllUserData[index].controlScheme == scheme) { return; } s_AllUserData[index].controlScheme = scheme; Notify(user, InputUserChange.ControlSchemeChanged); }
//do we really need a stack on this? is a single InputActionMap or even a list of InputActionMaps not enough? //what's the problem that the stack here is trying to solve? /// <summary> /// Get the <see cref="InputAction">input actions</see> that are currently active for the user. /// </summary> public static InputActionStack GetInputActions(this IInputUser user) { if (user == null) { throw new ArgumentNullException("user"); } var index = FindUserIndex(user); if (index == -1) { return(null); } var result = s_AllUserData[index].actionStack; if (result == null) { result = new InputActionStack(); s_AllUserData[index].actionStack = result; } return(result); }
private async Task<IUser> GetUser(IInputUser user, TelegramClient client) { return (await GetUsers(new List<IInputUser> { user }, client)).First(); }
public static void ResetHaptics(this IInputUser user) { ////TODO }
public static void SetUserHandle(this IInputUser user, InputUserHandle?handle) { throw new NotImplementedException(); }
public static void ResetHaptics(this IInputUser user) { throw new NotImplementedException(); }
public static void PauseHaptics(this IInputUser user) { ////TODO }
public void Users_CanDetectWhenUnassignedDeviceIsUsed() { var gamepad1 = InputSystem.AddDevice <Gamepad>(); var gamepad2 = InputSystem.AddDevice <Gamepad>(); var gamepad3 = InputSystem.AddDevice <Gamepad>(); var asset = ScriptableObject.CreateInstance <InputActionAsset>(); var map = new InputActionMap("map"); asset.AddActionMap(map); var actionAssignedToUser = map.AddAction("action", binding: "<Gamepad>/buttonSouth"); actionAssignedToUser.Enable(); var actionNotAssignedToUser = new InputAction(binding: "<Gamepad>/buttonNorth"); actionNotAssignedToUser.Enable(); var user = new TestUser(); InputUser.Add(user); // Noise. InputUser.Add(new TestUser()); InputUser.all[1].AssignInputDevice(gamepad3); IInputUser receivedUser = null; InputAction receivedAction = null; InputControl receivedControl = null; InputUser.onUnassignedDeviceUsed += (u, a, c) => { Assert.That(receivedUser, Is.Null); receivedUser = u; receivedAction = a; receivedControl = c; }; user.AssignInputActions(asset); user.AssignInputDevice(gamepad1); // No callback if using gamepad1. InputSystem.QueueStateEvent(gamepad1, new GamepadState().WithButton(GamepadButton.South)); InputSystem.Update(); Assert.That(receivedUser, Is.Null); Assert.That(receivedAction, Is.Null); Assert.That(receivedControl, Is.Null); // Callback when using gamepad2. InputSystem.QueueStateEvent(gamepad2, new GamepadState().WithButton(GamepadButton.South)); InputSystem.Update(); Assert.That(receivedUser, Is.SameAs(user)); Assert.That(receivedAction, Is.SameAs(actionAssignedToUser)); Assert.That(receivedControl, Is.SameAs(gamepad2.buttonSouth)); receivedUser = null; receivedControl = null; receivedAction = null; // No callback when triggering action not assigned to user. InputSystem.QueueStateEvent(gamepad1, new GamepadState().WithButton(GamepadButton.North)); InputSystem.Update(); Assert.That(receivedUser, Is.Null); Assert.That(receivedAction, Is.Null); Assert.That(receivedControl, Is.Null); }
public void Users_CanBeMonitoredForChanges() { InputUser.Add(new TestUser()); // Noise. InputUser.Add(new TestUser()); // Noise. var user = new TestUser(); IInputUser receivedUser = null; InputUserChange?receivedChange = null; InputUser.onChange += (usr, change) => { Assert.That(receivedChange == null); receivedUser = usr; receivedChange = change; }; // Added. InputUser.Add(user); Assert.That(receivedUser, Is.SameAs(user)); Assert.That(receivedChange, Is.EqualTo(InputUserChange.Added)); receivedUser = null; receivedChange = null; // NameChanged. user.SetUserName("NewName"); Assert.That(receivedUser, Is.SameAs(user)); Assert.That(receivedChange, Is.EqualTo(InputUserChange.NameChanged)); receivedUser = null; receivedChange = null; // HandleChanged. user.SetUserHandle(new InputUserHandle("test", 1)); Assert.That(receivedUser, Is.SameAs(user)); Assert.That(receivedChange, Is.EqualTo(InputUserChange.HandleChanged)); receivedUser = null; receivedChange = null; // Same name, no notification. user.SetUserName("NewName"); Assert.That(receivedChange, Is.Null); // DevicesChanged. var device = InputSystem.AddDevice <Gamepad>(); user.AssignInputDevice(device); Assert.That(receivedUser, Is.SameAs(user)); Assert.That(receivedChange, Is.EqualTo(InputUserChange.DevicesChanged)); receivedUser = null; receivedChange = null; // Same device, no notification. user.AssignInputDevice(device); Assert.That(receivedChange, Is.Null); // DevicesChanges, removed. user.ClearAssignedInputDevices(); Assert.That(receivedUser, Is.SameAs(user)); Assert.That(receivedChange, Is.EqualTo(InputUserChange.DevicesChanged)); receivedUser = null; receivedChange = null; // ControlSchemeChanged. user.AssignControlScheme("gamepad"); Assert.That(receivedUser, Is.SameAs(user)); Assert.That(receivedChange, Is.EqualTo(InputUserChange.ControlSchemeChanged)); receivedUser = null; receivedChange = null; // Same control scheme, no notification. user.AssignControlScheme("gamepad"); Assert.That(receivedChange, Is.Null); // Removed. InputUser.Remove(user); Assert.That(receivedUser, Is.SameAs(user)); Assert.That(receivedChange, Is.EqualTo(InputUserChange.Removed)); ////TODO: actions ////TODO: activate, passivate }