@quenty/inputmode 5.2.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/package.json +3 -3
- package/src/Client/InputMode.lua +18 -35
- package/src/Client/InputModeProcessor.lua +10 -5
- package/src/Client/InputModeServiceClient.lua +115 -0
- package/src/Client/InputModeTypeSelector.lua +242 -0
- package/src/Shared/InputModeType.lua +81 -0
- package/src/{Client/INPUT_MODES.lua → Shared/InputModeTypes.lua} +38 -112
- package/src/Client/InputModeSelector.lua +0 -229
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [6.0.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/inputmode@5.2.0...@quenty/inputmode@6.0.0) (2022-08-14)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @quenty/inputmode
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
6
14
|
# [5.2.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/inputmode@5.1.0...@quenty/inputmode@5.2.0) (2022-07-31)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @quenty/inputmode
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/inputmode",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "Trace input mode state and trigger changes correctly",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"@quenty/maid": "^2.4.0",
|
|
30
30
|
"@quenty/signal": "^2.2.0",
|
|
31
31
|
"@quenty/table": "^3.1.0",
|
|
32
|
-
"@quenty/valueobject": "^
|
|
32
|
+
"@quenty/valueobject": "^6.0.0"
|
|
33
33
|
},
|
|
34
34
|
"publishConfig": {
|
|
35
35
|
"access": "public"
|
|
36
36
|
},
|
|
37
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "dbb62609f980983cc32da90acfef13e30ed41113"
|
|
38
38
|
}
|
package/src/Client/InputMode.lua
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
--[=[
|
|
2
2
|
Trace input mode state and trigger changes correctly. See [InputModeSelector] for details
|
|
3
|
-
on how to select between these. See [
|
|
3
|
+
on how to select between these. See [InputModeTypeTypes] for predefined modes.
|
|
4
4
|
|
|
5
5
|
@class InputMode
|
|
6
6
|
]=]
|
|
@@ -26,23 +26,21 @@ InputMode.__index = InputMode
|
|
|
26
26
|
InputMode.ClassName = "InputMode"
|
|
27
27
|
|
|
28
28
|
--[=[
|
|
29
|
-
Constructs a new InputMode
|
|
29
|
+
Constructs a new InputMode. This inherits data from the name.
|
|
30
30
|
|
|
31
|
-
@param
|
|
32
|
-
@param typesAndInputModes { { UserInputType | KeyCode | string | InputMode } }
|
|
31
|
+
@param inputModeType InputModeType
|
|
33
32
|
@return InputMode
|
|
34
33
|
]=]
|
|
35
|
-
function InputMode.new(
|
|
34
|
+
function InputMode.new(inputModeType)
|
|
36
35
|
local self = setmetatable({}, InputMode)
|
|
37
36
|
|
|
37
|
+
self._inputModeType = assert(inputModeType, "Bad inputModeType")
|
|
38
|
+
|
|
38
39
|
self._lastEnabled = 0
|
|
39
|
-
self._valid = {}
|
|
40
40
|
|
|
41
|
-
self.Name =
|
|
41
|
+
self.Name = self._inputModeType.Name
|
|
42
42
|
self.Enabled = Signal.new()
|
|
43
43
|
|
|
44
|
-
self:_addValidTypesFromTable(typesAndInputModes)
|
|
45
|
-
|
|
46
44
|
return self
|
|
47
45
|
end
|
|
48
46
|
|
|
@@ -63,34 +61,12 @@ function InputMode:GetLastEnabledTime()
|
|
|
63
61
|
return self._lastEnabled
|
|
64
62
|
end
|
|
65
63
|
|
|
66
|
-
function InputMode:_addValidTypesFromTable(keys)
|
|
67
|
-
for _, key in pairs(keys) do
|
|
68
|
-
if typeof(key) == "EnumItem" then
|
|
69
|
-
self._valid[key] = true
|
|
70
|
-
elseif type(key) == "table" then
|
|
71
|
-
self:_addInputMode(key)
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
function InputMode:_addInputMode(inputMode)
|
|
77
|
-
assert(inputMode.ClassName == "InputMode", "bad inputMode")
|
|
78
|
-
|
|
79
|
-
for key, _ in pairs(inputMode._valid) do
|
|
80
|
-
self._valid[key] = true
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
64
|
--[=[
|
|
85
65
|
Returns all keys defining the input mode.
|
|
86
66
|
@return { UserInputType | KeyCode | string }
|
|
87
67
|
]=]
|
|
88
68
|
function InputMode:GetKeys()
|
|
89
|
-
|
|
90
|
-
for key, _ in pairs(self._valid) do
|
|
91
|
-
table.insert(keys, key)
|
|
92
|
-
end
|
|
93
|
-
return keys
|
|
69
|
+
return self._inputModeType:GetKeys()
|
|
94
70
|
end
|
|
95
71
|
|
|
96
72
|
--[=[
|
|
@@ -101,7 +77,7 @@ end
|
|
|
101
77
|
function InputMode:IsValid(inputType)
|
|
102
78
|
assert(inputType, "Must send in inputType")
|
|
103
79
|
|
|
104
|
-
return self.
|
|
80
|
+
return self._inputModeType:IsValid(inputType)
|
|
105
81
|
end
|
|
106
82
|
|
|
107
83
|
--[=[
|
|
@@ -117,11 +93,18 @@ end
|
|
|
117
93
|
@param inputObject InputObject
|
|
118
94
|
]=]
|
|
119
95
|
function InputMode:Evaluate(inputObject)
|
|
120
|
-
if self.
|
|
121
|
-
or self.
|
|
96
|
+
if self._inputModeType:IsValid(inputObject.UserInputType)
|
|
97
|
+
or self._inputModeType:IsValid(inputObject.KeyCode) then
|
|
122
98
|
|
|
123
99
|
self:Enable()
|
|
124
100
|
end
|
|
125
101
|
end
|
|
126
102
|
|
|
103
|
+
--[=[
|
|
104
|
+
Cleans up the input mode
|
|
105
|
+
]=]
|
|
106
|
+
function InputMode:Destroy()
|
|
107
|
+
self.Enabled:Destroy()
|
|
108
|
+
end
|
|
109
|
+
|
|
127
110
|
return InputMode
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
--[=[
|
|
2
|
-
Process inputs by evaluating inputModes.
|
|
3
|
-
use modes from INPUT_MODES.
|
|
2
|
+
Process inputs by evaluating inputModes. Helper object..
|
|
4
3
|
|
|
5
4
|
@class InputModeProcessor
|
|
6
5
|
]=]
|
|
@@ -11,7 +10,7 @@ InputModeProcessor.ClassName = InputModeProcessor
|
|
|
11
10
|
|
|
12
11
|
--[=[
|
|
13
12
|
Construtcs a new inputModeProcessor
|
|
14
|
-
@param inputModes { InputMode }
|
|
13
|
+
@param inputModes { InputMode }?
|
|
15
14
|
@return InputModeProcessor
|
|
16
15
|
]=]
|
|
17
16
|
function InputModeProcessor.new(inputModes)
|
|
@@ -19,13 +18,19 @@ function InputModeProcessor.new(inputModes)
|
|
|
19
18
|
|
|
20
19
|
self._inputModes = {}
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
if inputModes then
|
|
22
|
+
for _, inputMode in pairs(inputModes) do
|
|
23
|
+
self:AddInputMode(inputMode)
|
|
24
|
+
end
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
return self
|
|
27
28
|
end
|
|
28
29
|
|
|
30
|
+
function InputModeProcessor:AddInputMode(inputMode)
|
|
31
|
+
table.insert(self._inputModes, inputMode)
|
|
32
|
+
end
|
|
33
|
+
|
|
29
34
|
--[=[
|
|
30
35
|
Gets all input mode inputModes being used
|
|
31
36
|
@return { InputMode }
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
--[=[
|
|
2
|
+
Centralized
|
|
3
|
+
@class InputModeServiceClient
|
|
4
|
+
]=]
|
|
5
|
+
|
|
6
|
+
local require = require(script.Parent.loader).load(script)
|
|
7
|
+
|
|
8
|
+
local UserInputService = game:GetService("UserInputService")
|
|
9
|
+
local GuiService = game:GetService("GuiService")
|
|
10
|
+
|
|
11
|
+
local InputModeType = require("InputModeType")
|
|
12
|
+
local Maid = require("Maid")
|
|
13
|
+
local InputModeProcessor = require("InputModeProcessor")
|
|
14
|
+
local InputModeTypes = require("InputModeTypes")
|
|
15
|
+
local InputMode = require("InputMode")
|
|
16
|
+
|
|
17
|
+
local THUMBSTICK_DEADZONE = 0.14
|
|
18
|
+
|
|
19
|
+
local InputModeServiceClient = {}
|
|
20
|
+
InputModeServiceClient.ServiceName = "InputModeServiceClient"
|
|
21
|
+
|
|
22
|
+
function InputModeServiceClient:Init(serviceBag)
|
|
23
|
+
assert(not self._serviceBag, "Already initialized")
|
|
24
|
+
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
25
|
+
|
|
26
|
+
self._maid = Maid.new()
|
|
27
|
+
self._inputModes = {}
|
|
28
|
+
|
|
29
|
+
self._inputModeProcessor = InputModeProcessor.new()
|
|
30
|
+
|
|
31
|
+
-- order semi-matters. general should come first, to non-specific. that way, specific stuff has
|
|
32
|
+
-- priority over non-specific input modes.
|
|
33
|
+
self:GetInputMode(InputModeTypes.KeyboardAndMouse);
|
|
34
|
+
self:GetInputMode(InputModeTypes.Gamepads);
|
|
35
|
+
self:GetInputMode(InputModeTypes.Keyboard);
|
|
36
|
+
self:GetInputMode(InputModeTypes.Touch);
|
|
37
|
+
self:GetInputMode(InputModeTypes.Mouse);
|
|
38
|
+
self:GetInputMode(InputModeTypes.ArrowKeys);
|
|
39
|
+
self:GetInputMode(InputModeTypes.Keypad);
|
|
40
|
+
self:GetInputMode(InputModeTypes.WASD);
|
|
41
|
+
self:GetInputMode(InputModeTypes.DPad);
|
|
42
|
+
-- Don't add InputModeTypes.Thumbsticks, we handle it seperately
|
|
43
|
+
|
|
44
|
+
self:_triggerEnabled()
|
|
45
|
+
self:_bindProcessor()
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
function InputModeServiceClient:GetInputMode(inputModeType)
|
|
49
|
+
assert(InputModeType.isInputModeType(inputModeType), "Bad inputModeType")
|
|
50
|
+
|
|
51
|
+
if self._inputModes[inputModeType] then
|
|
52
|
+
return self._inputModes[inputModeType]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
local inputMode = InputMode.new(inputModeType)
|
|
56
|
+
self._maid:GiveTask(inputMode)
|
|
57
|
+
|
|
58
|
+
self._inputModes[inputModeType] = inputMode
|
|
59
|
+
return inputMode
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
function InputModeServiceClient:_triggerEnabled()
|
|
63
|
+
if UserInputService.MouseEnabled then
|
|
64
|
+
self:GetInputMode(InputModeTypes.Mouse):Enable()
|
|
65
|
+
end
|
|
66
|
+
if UserInputService.TouchEnabled then
|
|
67
|
+
self:GetInputMode(InputModeTypes.Touch):Enable()
|
|
68
|
+
end
|
|
69
|
+
if UserInputService.KeyboardEnabled then
|
|
70
|
+
self:GetInputMode(InputModeTypes.Keyboard):Enable()
|
|
71
|
+
end
|
|
72
|
+
if UserInputService.KeyboardEnabled and UserInputService.MouseEnabled then
|
|
73
|
+
self:GetInputMode(InputModeTypes.KeyboardAndMouse):Enable()
|
|
74
|
+
end
|
|
75
|
+
if UserInputService.GamepadEnabled
|
|
76
|
+
or #UserInputService:GetConnectedGamepads() > 0
|
|
77
|
+
or GuiService:IsTenFootInterface() then
|
|
78
|
+
self:GetInputMode(InputModeTypes.Gamepads):Enable()
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
function InputModeServiceClient:_bindProcessor()
|
|
83
|
+
self._maid:GiveTask(UserInputService.InputBegan:Connect(function(inputObject)
|
|
84
|
+
self._inputModeProcessor:Evaluate(inputObject)
|
|
85
|
+
end))
|
|
86
|
+
self._maid:GiveTask(UserInputService.InputEnded:Connect(function(inputObject)
|
|
87
|
+
self._inputModeProcessor:Evaluate(inputObject)
|
|
88
|
+
end))
|
|
89
|
+
self._maid:GiveTask(UserInputService.InputChanged:Connect(function(inputObject)
|
|
90
|
+
if inputObject.KeyCode == Enum.KeyCode.Thumbstick1
|
|
91
|
+
or inputObject.KeyCode == Enum.KeyCode.Thumbstick2 then
|
|
92
|
+
|
|
93
|
+
if inputObject.Position.magnitude > THUMBSTICK_DEADZONE then
|
|
94
|
+
self._inputModeProcessor:Evaluate(inputObject)
|
|
95
|
+
self:GetInputMode(InputModeTypes.Thumbsticks):Enable()
|
|
96
|
+
end
|
|
97
|
+
else
|
|
98
|
+
self._inputModeProcessor:Evaluate(inputObject)
|
|
99
|
+
end
|
|
100
|
+
end))
|
|
101
|
+
|
|
102
|
+
self._maid:GiveTask(UserInputService.GamepadConnected:Connect(function(_)
|
|
103
|
+
self:GetInputMode(InputModeTypes.Gamepads):Enable()
|
|
104
|
+
end))
|
|
105
|
+
|
|
106
|
+
self._maid:GiveTask(UserInputService.GamepadDisconnected:Connect(function(_)
|
|
107
|
+
self:_triggerEnabled()
|
|
108
|
+
end))
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
function InputModeServiceClient:Destroy()
|
|
112
|
+
self._maid:DoCleaning()
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
return InputModeServiceClient
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
--[=[
|
|
2
|
+
Selects the most recent input mode and attempts to identify the best state from it.
|
|
3
|
+
@class InputModeTypeSelector
|
|
4
|
+
]=]
|
|
5
|
+
|
|
6
|
+
local require = require(script.Parent.loader).load(script)
|
|
7
|
+
|
|
8
|
+
local InputModeTypes = require("InputModeTypes")
|
|
9
|
+
local Maid = require("Maid")
|
|
10
|
+
local ValueObject = require("ValueObject")
|
|
11
|
+
local InputModeServiceClient = require("InputModeServiceClient")
|
|
12
|
+
local ServiceBag = require("ServiceBag")
|
|
13
|
+
|
|
14
|
+
local InputModeTypeSelector = {}
|
|
15
|
+
InputModeTypeSelector.ClassName = "InputModeTypeSelector"
|
|
16
|
+
InputModeTypeSelector.DEFAULT_MODE_TYPES = {
|
|
17
|
+
InputModeTypes.Gamepads,
|
|
18
|
+
InputModeTypes.Keyboard,
|
|
19
|
+
InputModeTypes.Touch
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
--[=[
|
|
23
|
+
Constructs a new InputModeTypeSelector
|
|
24
|
+
|
|
25
|
+
@param serviceBag ServiceBag
|
|
26
|
+
@param inputModesTypes { InputModeType }
|
|
27
|
+
@return InputModeTypeSelector
|
|
28
|
+
]=]
|
|
29
|
+
function InputModeTypeSelector.new(serviceBag, inputModesTypes)
|
|
30
|
+
local self = setmetatable({}, InputModeTypeSelector)
|
|
31
|
+
|
|
32
|
+
assert(ServiceBag.isServiceBag(serviceBag), "Bad serviceBag")
|
|
33
|
+
|
|
34
|
+
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
35
|
+
|
|
36
|
+
self._inputModeServiceClient = self._serviceBag:GetService(InputModeServiceClient)
|
|
37
|
+
|
|
38
|
+
self._maid = Maid.new()
|
|
39
|
+
|
|
40
|
+
-- keep this ordered so we are always stable in selection.
|
|
41
|
+
self._inputModeTypeList = {}
|
|
42
|
+
|
|
43
|
+
self._activeModeType = ValueObject.new()
|
|
44
|
+
self._maid:GiveTask(self._activeModeType)
|
|
45
|
+
|
|
46
|
+
--[=[
|
|
47
|
+
Event that fires whenever the active mode changes.
|
|
48
|
+
@prop Changed Signal<InputModeType, InputModeType> -- newMode, oldMode
|
|
49
|
+
@within InputModeTypeSelector
|
|
50
|
+
]=]
|
|
51
|
+
self.Changed = self._activeModeType.Changed
|
|
52
|
+
|
|
53
|
+
for _, inputModeType in pairs(inputModesTypes or InputModeTypeSelector.DEFAULT_MODE_TYPES) do
|
|
54
|
+
self:AddInputModeType(inputModeType)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
return self
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
--[=[
|
|
61
|
+
Constructs a new InputModeTypeSelector
|
|
62
|
+
|
|
63
|
+
@param serviceBag ServiceBag
|
|
64
|
+
@param observeInputModesBrio Observable<Brio<InputModeType>>
|
|
65
|
+
@return InputModeTypeSelector
|
|
66
|
+
]=]
|
|
67
|
+
function InputModeTypeSelector.fromObservableBrio(serviceBag, observeInputModesBrio)
|
|
68
|
+
local selector = InputModeTypeSelector.new(serviceBag, {})
|
|
69
|
+
|
|
70
|
+
selector._maid:GiveTask(observeInputModesBrio:Subscribe(function(brio)
|
|
71
|
+
if brio:IsDead() then
|
|
72
|
+
return
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
local inputModeType = brio:GetValue()
|
|
76
|
+
local maid = brio:ToMaid()
|
|
77
|
+
selector:AddInputModeType(inputModeType)
|
|
78
|
+
|
|
79
|
+
maid:GiveTask(function()
|
|
80
|
+
if selector.Destroy then
|
|
81
|
+
selector:RemoveInputModeType(inputModeType)
|
|
82
|
+
end
|
|
83
|
+
end)
|
|
84
|
+
end))
|
|
85
|
+
|
|
86
|
+
return selector
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
--[=[
|
|
90
|
+
Returns the current active mode
|
|
91
|
+
@return InputModeType
|
|
92
|
+
]=]
|
|
93
|
+
function InputModeTypeSelector:GetActiveInputType()
|
|
94
|
+
return rawget(self, "_activeModeType").Value
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
--[=[
|
|
98
|
+
Observes the current active mode
|
|
99
|
+
@return Observable<InputModeType>
|
|
100
|
+
]=]
|
|
101
|
+
function InputModeTypeSelector:ObserveActiveInputType()
|
|
102
|
+
return rawget(self, "_activeModeType"):Observe()
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
--[=[
|
|
106
|
+
The current active input mode
|
|
107
|
+
@prop Value InputModeType?
|
|
108
|
+
@within InputModeTypeSelector
|
|
109
|
+
]=]
|
|
110
|
+
function InputModeTypeSelector:__index(index)
|
|
111
|
+
if index == "Value" then
|
|
112
|
+
return rawget(self, "_activeModeType").Value
|
|
113
|
+
elseif InputModeTypeSelector[index] then
|
|
114
|
+
return InputModeTypeSelector[index]
|
|
115
|
+
else
|
|
116
|
+
local value = rawget(self, index)
|
|
117
|
+
if value then
|
|
118
|
+
return value
|
|
119
|
+
else
|
|
120
|
+
error(("[InputModeTypeSelector] - Bad index '%s'"):format(tostring(index)))
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
--[=[
|
|
126
|
+
Binds the updateBindFunction to the mode selector
|
|
127
|
+
|
|
128
|
+
```lua
|
|
129
|
+
local inputModeTypeSelector = InputModeTypeSelector.new({
|
|
130
|
+
InputModeTypes.Mouse;
|
|
131
|
+
InputModeTypes.Touch;
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
inputModeTypeSelector:Bind(function(inputModeType)
|
|
135
|
+
if inputModeType == InputModeTypes.Mouse then
|
|
136
|
+
print("Show mouse input hints")
|
|
137
|
+
elseif inputModeType == InputModeTypes.Touch then
|
|
138
|
+
print("Show touch input hints")
|
|
139
|
+
else
|
|
140
|
+
-- Unknown input mode
|
|
141
|
+
warn("Unknown input mode") -- should not occur
|
|
142
|
+
end
|
|
143
|
+
end)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
@param updateBindFunction (newMode: InputModeType, modeMaid: Maid) -> ()
|
|
147
|
+
@return InputModeTypeSelector
|
|
148
|
+
]=]
|
|
149
|
+
function InputModeTypeSelector:Bind(updateBindFunction)
|
|
150
|
+
local maid = Maid.new()
|
|
151
|
+
self._maid[updateBindFunction] = maid
|
|
152
|
+
|
|
153
|
+
local function onChange(newMode, _)
|
|
154
|
+
maid._modeMaid = nil
|
|
155
|
+
|
|
156
|
+
if newMode then
|
|
157
|
+
local modeMaid = Maid.new()
|
|
158
|
+
maid._modeMaid = modeMaid
|
|
159
|
+
|
|
160
|
+
if newMode then
|
|
161
|
+
updateBindFunction(newMode, modeMaid)
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
maid:GiveTask(self._activeModeType.Changed:Connect(onChange))
|
|
167
|
+
onChange(self._activeModeType.Value, nil)
|
|
168
|
+
|
|
169
|
+
return self
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
--[=[
|
|
173
|
+
Removes the input mode
|
|
174
|
+
@param inputModeType InputModeType
|
|
175
|
+
]=]
|
|
176
|
+
function InputModeTypeSelector:RemoveInputModeType(inputModeType)
|
|
177
|
+
if not self._maid[inputModeType] then
|
|
178
|
+
return
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
local index = table.find(self._inputModeTypeList, inputModeType)
|
|
182
|
+
if index then
|
|
183
|
+
table.remove(self._inputModeTypeList, index)
|
|
184
|
+
else
|
|
185
|
+
warn("[InputModeTypeSelector] - Failed to find inputModeType")
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
self._maid[inputModeType] = nil
|
|
189
|
+
|
|
190
|
+
if self._activeModeType.Value == inputModeType then
|
|
191
|
+
self:_pickNewInputMode()
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
--[=[
|
|
196
|
+
Adds a new input mode
|
|
197
|
+
@param inputModeType InputModeType
|
|
198
|
+
]=]
|
|
199
|
+
function InputModeTypeSelector:AddInputModeType(inputModeType)
|
|
200
|
+
if self._maid[inputModeType] then
|
|
201
|
+
return
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
table.insert(self._inputModeTypeList, inputModeType)
|
|
205
|
+
local inputMode = self._inputModeServiceClient:GetInputMode(inputModeType)
|
|
206
|
+
self._maid[inputModeType] = inputMode.Enabled:Connect(function()
|
|
207
|
+
self._activeModeType.Value = inputModeType
|
|
208
|
+
end)
|
|
209
|
+
|
|
210
|
+
if not self._activeModeType.Value
|
|
211
|
+
or inputMode:GetLastEnabledTime() > self._inputModeServiceClient:GetInputMode(self._activeModeType.Value):GetLastEnabledTime() then
|
|
212
|
+
self._activeModeType.Value = inputModeType
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
function InputModeTypeSelector:_pickNewInputMode()
|
|
217
|
+
local bestEnabledTime = -math.huge
|
|
218
|
+
local bestModeType
|
|
219
|
+
for _, inputModeType in pairs(self._inputModeTypeList) do
|
|
220
|
+
local enableTime = self._inputModeServiceClient:GetInputMode(inputModeType):GetLastEnabledTime()
|
|
221
|
+
if enableTime >= bestEnabledTime then
|
|
222
|
+
bestEnabledTime = enableTime
|
|
223
|
+
bestModeType = inputModeType
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
self._activeModeType.Value = bestModeType
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
--[=[
|
|
231
|
+
Cleans up the input mode selector.
|
|
232
|
+
|
|
233
|
+
:::info
|
|
234
|
+
This should be called whenever the mode selector is done being used.
|
|
235
|
+
:::
|
|
236
|
+
]=]
|
|
237
|
+
function InputModeTypeSelector:Destroy()
|
|
238
|
+
self._maid:DoCleaning()
|
|
239
|
+
setmetatable(self, nil)
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
return InputModeTypeSelector
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
--[=[
|
|
2
|
+
Type specification for input modes, which is static. Separated out from InputMode which is dynamic.
|
|
3
|
+
|
|
4
|
+
@class InputModeType
|
|
5
|
+
]=]
|
|
6
|
+
|
|
7
|
+
local InputModeType = {}
|
|
8
|
+
InputModeType.ClassName = "InputModeType"
|
|
9
|
+
InputModeType.__index = InputModeType
|
|
10
|
+
|
|
11
|
+
--[=[
|
|
12
|
+
Constructs a new InputModeType
|
|
13
|
+
|
|
14
|
+
@param name string
|
|
15
|
+
@param typesAndInputModes { { UserInputType | KeyCode | string | InputMode } }
|
|
16
|
+
@return InputMode
|
|
17
|
+
]=]
|
|
18
|
+
function InputModeType.new(name, typesAndInputModes)
|
|
19
|
+
local self = setmetatable({}, InputModeType)
|
|
20
|
+
|
|
21
|
+
self._valid = {}
|
|
22
|
+
self.Name = name or "Unnamed"
|
|
23
|
+
|
|
24
|
+
self:_addValidTypesFromTable(typesAndInputModes)
|
|
25
|
+
|
|
26
|
+
return self
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
--[=[
|
|
30
|
+
Returns true if a given value is an InputModeType
|
|
31
|
+
@param value any
|
|
32
|
+
@return boolean
|
|
33
|
+
]=]
|
|
34
|
+
function InputModeType.isInputModeType(value)
|
|
35
|
+
return type(value) == "table" and getmetatable(value) == InputModeType
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
--[=[
|
|
39
|
+
Checks the validity of the inputType
|
|
40
|
+
@param inputType { UserInputType | KeyCode | string }
|
|
41
|
+
@return boolean
|
|
42
|
+
]=]
|
|
43
|
+
function InputModeType:IsValid(inputType)
|
|
44
|
+
assert(inputType, "Must send in inputType")
|
|
45
|
+
|
|
46
|
+
return self._valid[inputType]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
--[=[
|
|
50
|
+
Returns all keys defining the input mode.
|
|
51
|
+
@return { UserInputType | KeyCode | string }
|
|
52
|
+
]=]
|
|
53
|
+
function InputModeType:GetKeys()
|
|
54
|
+
local keys = {}
|
|
55
|
+
for key, _ in pairs(self._valid) do
|
|
56
|
+
table.insert(keys, key)
|
|
57
|
+
end
|
|
58
|
+
return keys
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
function InputModeType:_addValidTypesFromTable(keys)
|
|
62
|
+
for _, key in pairs(keys) do
|
|
63
|
+
if typeof(key) == "EnumItem" then
|
|
64
|
+
self._valid[key] = true
|
|
65
|
+
elseif InputModeType.isInputModeType(key) then
|
|
66
|
+
self:_addInputModeType(key)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
function InputModeType:_addInputModeType(inputModeType)
|
|
72
|
+
assert(InputModeType.isInputModeType(inputModeType), "Bad inputModeType")
|
|
73
|
+
|
|
74
|
+
for key, _ in pairs(inputModeType._valid) do
|
|
75
|
+
self._valid[key] = true
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
return InputModeType
|
|
@@ -1,31 +1,22 @@
|
|
|
1
1
|
--[=[
|
|
2
|
-
Holds input
|
|
3
|
-
|
|
4
|
-
how to select between several modes.
|
|
5
|
-
|
|
6
|
-
@class INPUT_MODES
|
|
2
|
+
Holds all the input mode type configuration, accessible on both the server and the client for keybinding validations.
|
|
3
|
+
@class InputModeTypes
|
|
7
4
|
]=]
|
|
8
5
|
|
|
9
|
-
local UserInputService = game:GetService("UserInputService")
|
|
10
|
-
local GuiService = game:GetService("GuiService")
|
|
11
|
-
|
|
12
6
|
local require = require(script.Parent.loader).load(script)
|
|
13
7
|
|
|
14
|
-
local InputMode = require("InputMode")
|
|
15
|
-
local InputModeProcessor = require("InputModeProcessor")
|
|
16
8
|
local Table = require("Table")
|
|
9
|
+
local InputModeType = require("InputModeType")
|
|
17
10
|
|
|
18
|
-
local
|
|
19
|
-
THUMBSTICK_DEADZONE = 0.14
|
|
20
|
-
}
|
|
11
|
+
local InputModeTypes = {}
|
|
21
12
|
|
|
22
13
|
--[=[
|
|
23
14
|
Input from a keypad
|
|
24
|
-
@prop Keypad
|
|
15
|
+
@prop Keypad InputModeType
|
|
25
16
|
@readonly
|
|
26
|
-
@within
|
|
17
|
+
@within InputModeTypes
|
|
27
18
|
]=]
|
|
28
|
-
|
|
19
|
+
InputModeTypes.Keypad = InputModeType.new("Keypad", {
|
|
29
20
|
Enum.KeyCode.KeypadZero;
|
|
30
21
|
Enum.KeyCode.KeypadOne;
|
|
31
22
|
Enum.KeyCode.KeypadTwo;
|
|
@@ -47,15 +38,15 @@ INPUT_MODES.Keypad = InputMode.new("Keypad", {
|
|
|
47
38
|
|
|
48
39
|
--[=[
|
|
49
40
|
Input from a keyboard
|
|
50
|
-
@prop Keyboard
|
|
41
|
+
@prop Keyboard InputModeType
|
|
51
42
|
@readonly
|
|
52
|
-
@within
|
|
43
|
+
@within InputModeTypes
|
|
53
44
|
]=]
|
|
54
|
-
|
|
45
|
+
InputModeTypes.Keyboard = InputModeType.new("Keyboard", {
|
|
55
46
|
Enum.UserInputType.Keyboard;
|
|
56
47
|
|
|
57
48
|
-- Other input modes
|
|
58
|
-
|
|
49
|
+
InputModeTypes.Keypad;
|
|
59
50
|
|
|
60
51
|
-- Valid KeyCodes for input binding
|
|
61
52
|
Enum.KeyCode.Backspace;
|
|
@@ -184,11 +175,11 @@ INPUT_MODES.Keyboard = InputMode.new("Keyboard", {
|
|
|
184
175
|
|
|
185
176
|
--[=[
|
|
186
177
|
Input involving arrow keys!
|
|
187
|
-
@prop ArrowKeys
|
|
178
|
+
@prop ArrowKeys InputModeType
|
|
188
179
|
@readonly
|
|
189
|
-
@within
|
|
180
|
+
@within InputModeTypes
|
|
190
181
|
]=]
|
|
191
|
-
|
|
182
|
+
InputModeTypes.ArrowKeys = InputModeType.new("ArrowKeys", {
|
|
192
183
|
Enum.KeyCode.Left;
|
|
193
184
|
Enum.KeyCode.Right;
|
|
194
185
|
Enum.KeyCode.Up;
|
|
@@ -197,11 +188,11 @@ INPUT_MODES.ArrowKeys = InputMode.new("ArrowKeys", {
|
|
|
197
188
|
|
|
198
189
|
--[=[
|
|
199
190
|
Input involving WASD
|
|
200
|
-
@prop WASD
|
|
191
|
+
@prop WASD InputModeType
|
|
201
192
|
@readonly
|
|
202
|
-
@within
|
|
193
|
+
@within InputModeTypes
|
|
203
194
|
]=]
|
|
204
|
-
|
|
195
|
+
InputModeTypes.WASD = InputModeType.new("WASD", {
|
|
205
196
|
Enum.KeyCode.W;
|
|
206
197
|
Enum.KeyCode.A;
|
|
207
198
|
Enum.KeyCode.S;
|
|
@@ -210,11 +201,11 @@ INPUT_MODES.WASD = InputMode.new("WASD", {
|
|
|
210
201
|
|
|
211
202
|
--[=[
|
|
212
203
|
Input involving the mouse
|
|
213
|
-
@prop Mouse
|
|
204
|
+
@prop Mouse InputModeType
|
|
214
205
|
@readonly
|
|
215
|
-
@within
|
|
206
|
+
@within InputModeTypes
|
|
216
207
|
]=]
|
|
217
|
-
|
|
208
|
+
InputModeTypes.Mouse = InputModeType.new("Mouse", {
|
|
218
209
|
Enum.UserInputType.MouseButton1;
|
|
219
210
|
Enum.UserInputType.MouseButton2;
|
|
220
211
|
Enum.UserInputType.MouseButton3;
|
|
@@ -224,31 +215,31 @@ INPUT_MODES.Mouse = InputMode.new("Mouse", {
|
|
|
224
215
|
|
|
225
216
|
--[=[
|
|
226
217
|
Input involving the keyboard OR mouse.
|
|
227
|
-
@prop KeyboardAndMoues
|
|
218
|
+
@prop KeyboardAndMoues InputModeType
|
|
228
219
|
@readonly
|
|
229
|
-
@within
|
|
220
|
+
@within InputModeTypes
|
|
230
221
|
]=]
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
222
|
+
InputModeTypes.KeyboardAndMouse = InputModeType.new("KeyboardAndMouse", {
|
|
223
|
+
InputModeTypes.Mouse;
|
|
224
|
+
InputModeTypes.Keyboard;
|
|
234
225
|
})
|
|
235
226
|
|
|
236
227
|
--[=[
|
|
237
228
|
Input involving touch input.
|
|
238
|
-
@prop Touch
|
|
229
|
+
@prop Touch InputModeType
|
|
239
230
|
@readonly
|
|
240
|
-
@within
|
|
231
|
+
@within InputModeTypes
|
|
241
232
|
]=]
|
|
242
|
-
|
|
233
|
+
InputModeTypes.Touch = InputModeType.new("Touch", {
|
|
243
234
|
Enum.UserInputType.Touch;
|
|
244
235
|
})
|
|
245
236
|
|
|
246
237
|
--[=[
|
|
247
|
-
@prop DPad
|
|
238
|
+
@prop DPad InputModeType
|
|
248
239
|
@readonly
|
|
249
|
-
@within
|
|
240
|
+
@within InputModeTypes
|
|
250
241
|
]=]
|
|
251
|
-
|
|
242
|
+
InputModeTypes.DPad = InputModeType.new("DPad", {
|
|
252
243
|
Enum.KeyCode.DPadLeft;
|
|
253
244
|
Enum.KeyCode.DPadRight;
|
|
254
245
|
Enum.KeyCode.DPadUp;
|
|
@@ -257,22 +248,22 @@ INPUT_MODES.DPad = InputMode.new("DPad", {
|
|
|
257
248
|
|
|
258
249
|
--[=[
|
|
259
250
|
Input involved thumbsticks.
|
|
260
|
-
@prop Thumbsticks
|
|
251
|
+
@prop Thumbsticks InputModeType
|
|
261
252
|
@readonly
|
|
262
|
-
@within
|
|
253
|
+
@within InputModeTypes
|
|
263
254
|
]=]
|
|
264
|
-
|
|
255
|
+
InputModeTypes.Thumbsticks = InputModeType.new("Thumbsticks", {
|
|
265
256
|
Enum.KeyCode.Thumbstick1;
|
|
266
257
|
Enum.KeyCode.Thumbstick2;
|
|
267
258
|
})
|
|
268
259
|
|
|
269
260
|
--[=[
|
|
270
261
|
Input involving gamepads
|
|
271
|
-
@prop Gamepads
|
|
262
|
+
@prop Gamepads InputModeType
|
|
272
263
|
@readonly
|
|
273
|
-
@within
|
|
264
|
+
@within InputModeTypes
|
|
274
265
|
]=]
|
|
275
|
-
|
|
266
|
+
InputModeTypes.Gamepads = InputModeType.new("Gamepads", {
|
|
276
267
|
Enum.UserInputType.Gamepad1;
|
|
277
268
|
Enum.UserInputType.Gamepad2;
|
|
278
269
|
Enum.UserInputType.Gamepad3;
|
|
@@ -301,69 +292,4 @@ INPUT_MODES.Gamepads = InputMode.new("Gamepads", {
|
|
|
301
292
|
Enum.KeyCode.DPadDown;
|
|
302
293
|
})
|
|
303
294
|
|
|
304
|
-
|
|
305
|
-
if UserInputService.MouseEnabled then
|
|
306
|
-
INPUT_MODES.Mouse:Enable()
|
|
307
|
-
end
|
|
308
|
-
if UserInputService.TouchEnabled then
|
|
309
|
-
INPUT_MODES.Touch:Enable()
|
|
310
|
-
end
|
|
311
|
-
if UserInputService.KeyboardEnabled then
|
|
312
|
-
INPUT_MODES.Keyboard:Enable()
|
|
313
|
-
end
|
|
314
|
-
if UserInputService.KeyboardEnabled and UserInputService.MouseEnabled then
|
|
315
|
-
INPUT_MODES.KeyboardAndMouse:Enable()
|
|
316
|
-
end
|
|
317
|
-
if UserInputService.GamepadEnabled
|
|
318
|
-
or #UserInputService:GetConnectedGamepads() > 0
|
|
319
|
-
or GuiService:IsTenFootInterface() then
|
|
320
|
-
INPUT_MODES.Gamepads:Enable()
|
|
321
|
-
end
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
local function bindProcessor()
|
|
325
|
-
local inputProcessor = InputModeProcessor.new({
|
|
326
|
-
INPUT_MODES.Keypad;
|
|
327
|
-
INPUT_MODES.Keyboard;
|
|
328
|
-
INPUT_MODES.Gamepads;
|
|
329
|
-
INPUT_MODES.Mouse;
|
|
330
|
-
INPUT_MODES.Touch;
|
|
331
|
-
INPUT_MODES.ArrowKeys;
|
|
332
|
-
INPUT_MODES.WASD;
|
|
333
|
-
INPUT_MODES.KeyboardAndMouse;
|
|
334
|
-
INPUT_MODES.DPad;
|
|
335
|
-
-- Don't add INPUT_MODES.Thumbsticks, we handle it seperately
|
|
336
|
-
})
|
|
337
|
-
|
|
338
|
-
UserInputService.InputBegan:Connect(function(inputObject)
|
|
339
|
-
inputProcessor:Evaluate(inputObject)
|
|
340
|
-
end)
|
|
341
|
-
UserInputService.InputEnded:Connect(function(inputObject)
|
|
342
|
-
inputProcessor:Evaluate(inputObject)
|
|
343
|
-
end)
|
|
344
|
-
UserInputService.InputChanged:Connect(function(inputObject)
|
|
345
|
-
if inputObject.KeyCode == Enum.KeyCode.Thumbstick1
|
|
346
|
-
or inputObject.KeyCode == Enum.KeyCode.Thumbstick2 then
|
|
347
|
-
|
|
348
|
-
if inputObject.Position.magnitude > INPUT_MODES.THUMBSTICK_DEADZONE then
|
|
349
|
-
inputProcessor:Evaluate(inputObject)
|
|
350
|
-
INPUT_MODES.Thumbsticks:Enable()
|
|
351
|
-
end
|
|
352
|
-
else
|
|
353
|
-
inputProcessor:Evaluate(inputObject)
|
|
354
|
-
end
|
|
355
|
-
end)
|
|
356
|
-
|
|
357
|
-
UserInputService.GamepadConnected:Connect(function(_)
|
|
358
|
-
INPUT_MODES.Gamepads:Enable()
|
|
359
|
-
end)
|
|
360
|
-
|
|
361
|
-
UserInputService.GamepadDisconnected:Connect(function(_)
|
|
362
|
-
triggerEnabled()
|
|
363
|
-
end)
|
|
364
|
-
end
|
|
365
|
-
|
|
366
|
-
bindProcessor()
|
|
367
|
-
triggerEnabled()
|
|
368
|
-
|
|
369
|
-
return Table.readonly(INPUT_MODES)
|
|
295
|
+
return Table.readonly(InputModeTypes)
|
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
--[=[
|
|
2
|
-
Selects the most recent input mode and attempts to identify the best state from it.
|
|
3
|
-
@class InputModeSelector
|
|
4
|
-
]=]
|
|
5
|
-
|
|
6
|
-
local require = require(script.Parent.loader).load(script)
|
|
7
|
-
|
|
8
|
-
local INPUT_MODES = require("INPUT_MODES")
|
|
9
|
-
local Maid = require("Maid")
|
|
10
|
-
local ValueObject = require("ValueObject")
|
|
11
|
-
|
|
12
|
-
local InputModeSelector = {}
|
|
13
|
-
InputModeSelector.ClassName = "InputModeSelector"
|
|
14
|
-
InputModeSelector.DEFAULT_MODES = {
|
|
15
|
-
INPUT_MODES.Gamepads,
|
|
16
|
-
INPUT_MODES.Keyboard,
|
|
17
|
-
INPUT_MODES.Touch
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
--[=[
|
|
21
|
-
Constructs a new InputModeSelector
|
|
22
|
-
@param inputModes { InputMode }
|
|
23
|
-
@return InputModeSelector
|
|
24
|
-
]=]
|
|
25
|
-
function InputModeSelector.new(inputModes)
|
|
26
|
-
local self = setmetatable({}, InputModeSelector)
|
|
27
|
-
|
|
28
|
-
self._maid = Maid.new()
|
|
29
|
-
|
|
30
|
-
-- keep this ordered so we are always stable in selection.
|
|
31
|
-
self._inputModeList = {}
|
|
32
|
-
|
|
33
|
-
self._activeMode = ValueObject.new()
|
|
34
|
-
self._maid:GiveTask(self._activeMode)
|
|
35
|
-
|
|
36
|
-
--[=[
|
|
37
|
-
Event that fires whenever the active mode changes.
|
|
38
|
-
@prop Changed Signal<InputMode, InputMode> -- newMode, oldMode
|
|
39
|
-
@within InputModeSelector
|
|
40
|
-
]=]
|
|
41
|
-
self.Changed = self._activeMode.Changed
|
|
42
|
-
|
|
43
|
-
for _, inputMode in pairs(inputModes or InputModeSelector.DEFAULT_MODES) do
|
|
44
|
-
self:AddInputMode(inputMode)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
return self
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
--[=[
|
|
51
|
-
Constructs a new InputModeSelector
|
|
52
|
-
@param observeInputModesBrio Observable<Brio<InputMode>>
|
|
53
|
-
@return InputModeSelector
|
|
54
|
-
]=]
|
|
55
|
-
function InputModeSelector.fromObservableBrio(observeInputModesBrio)
|
|
56
|
-
local selector = InputModeSelector.new({})
|
|
57
|
-
|
|
58
|
-
selector._maid:GiveTask(observeInputModesBrio:Subscribe(function(brio)
|
|
59
|
-
if brio:IsDead() then
|
|
60
|
-
return
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
local inputMode = brio:GetValue()
|
|
64
|
-
local maid = brio:ToMaid()
|
|
65
|
-
selector:AddInputMode(inputMode)
|
|
66
|
-
|
|
67
|
-
maid:GiveTask(function()
|
|
68
|
-
if selector.Destroy then
|
|
69
|
-
selector:RemoveInputMode(inputMode)
|
|
70
|
-
end
|
|
71
|
-
end)
|
|
72
|
-
end))
|
|
73
|
-
|
|
74
|
-
return selector
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
--[=[
|
|
78
|
-
Returns the current active mode
|
|
79
|
-
@return InputMode
|
|
80
|
-
]=]
|
|
81
|
-
function InputModeSelector:GetActiveMode()
|
|
82
|
-
return rawget(self, "_activeMode").Value
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
--[=[
|
|
86
|
-
Observes the current active mode
|
|
87
|
-
@return Observable<InputMode>
|
|
88
|
-
]=]
|
|
89
|
-
function InputModeSelector:ObserveActiveMode()
|
|
90
|
-
return rawget(self, "_activeMode"):Observe()
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
--[=[
|
|
94
|
-
The current active input mode
|
|
95
|
-
@prop Value InputMode?
|
|
96
|
-
@within InputModeSelector
|
|
97
|
-
]=]
|
|
98
|
-
function InputModeSelector:__index(index)
|
|
99
|
-
if index == "Value" then
|
|
100
|
-
return rawget(self, "_activeMode").Value
|
|
101
|
-
elseif InputModeSelector[index] then
|
|
102
|
-
return InputModeSelector[index]
|
|
103
|
-
else
|
|
104
|
-
local value = rawget(self, index)
|
|
105
|
-
if value then
|
|
106
|
-
return value
|
|
107
|
-
else
|
|
108
|
-
error(("[InputModeSelector] - Bad index '%s'"):format(tostring(index)))
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
--[=[
|
|
114
|
-
Binds the updateBindFunction to the mode selector
|
|
115
|
-
|
|
116
|
-
```lua
|
|
117
|
-
local inputModeSelector = InputModeSelector.new({
|
|
118
|
-
INPUT_MODES.Mouse;
|
|
119
|
-
INPUT_MODES.Touch;
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
inputModeSelector:Bind(function(inputMode)
|
|
123
|
-
if inputMode == INPUT_MODES.Mouse then
|
|
124
|
-
print("Show mouse input hints")
|
|
125
|
-
elseif inputMode == INPUT_MODES.Touch then
|
|
126
|
-
print("Show touch input hints")
|
|
127
|
-
else
|
|
128
|
-
-- Unknown input mode
|
|
129
|
-
warn("Unknown input mode") -- should not occur
|
|
130
|
-
end
|
|
131
|
-
end)
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
@param updateBindFunction (newMode: InputMode, modeMaid: Maid) -> ()
|
|
135
|
-
@return InputModeSelector
|
|
136
|
-
]=]
|
|
137
|
-
function InputModeSelector:Bind(updateBindFunction)
|
|
138
|
-
local maid = Maid.new()
|
|
139
|
-
self._maid[updateBindFunction] = maid
|
|
140
|
-
|
|
141
|
-
local function onChange(newMode, _)
|
|
142
|
-
maid._modeMaid = nil
|
|
143
|
-
|
|
144
|
-
if newMode then
|
|
145
|
-
local modeMaid = Maid.new()
|
|
146
|
-
maid._modeMaid = modeMaid
|
|
147
|
-
|
|
148
|
-
if newMode then
|
|
149
|
-
updateBindFunction(newMode, modeMaid)
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
maid:GiveTask(self._activeMode.Changed:Connect(onChange))
|
|
155
|
-
onChange(self._activeMode.Value, nil)
|
|
156
|
-
|
|
157
|
-
return self
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
--[=[
|
|
161
|
-
Removes the input mode
|
|
162
|
-
@param inputMode InputMode
|
|
163
|
-
]=]
|
|
164
|
-
function InputModeSelector:RemoveInputMode(inputMode)
|
|
165
|
-
if not self._maid[inputMode] then
|
|
166
|
-
return
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
local index = table.find(self._inputModeList, inputMode)
|
|
170
|
-
if index then
|
|
171
|
-
table.remove(self._inputModeList, index)
|
|
172
|
-
else
|
|
173
|
-
warn("[InputModeSelector] - Failed to find inputMode")
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
self._maid[inputMode] = nil
|
|
177
|
-
|
|
178
|
-
if self._activeMode.Value == inputMode then
|
|
179
|
-
self:_pickNewInputMode()
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
--[=[
|
|
184
|
-
Adds a new input mode
|
|
185
|
-
@param inputMode InputMode
|
|
186
|
-
]=]
|
|
187
|
-
function InputModeSelector:AddInputMode(inputMode)
|
|
188
|
-
if self._maid[inputMode] then
|
|
189
|
-
return
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
table.insert(self._inputModeList, inputMode)
|
|
193
|
-
self._maid[inputMode] = inputMode.Enabled:Connect(function()
|
|
194
|
-
self._activeMode.Value = inputMode
|
|
195
|
-
end)
|
|
196
|
-
|
|
197
|
-
if not self._activeMode.Value
|
|
198
|
-
or inputMode:GetLastEnabledTime() > self._activeMode.Value:GetLastEnabledTime() then
|
|
199
|
-
self._activeMode.Value = inputMode
|
|
200
|
-
end
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
function InputModeSelector:_pickNewInputMode()
|
|
204
|
-
local bestEnabledTime = -math.huge
|
|
205
|
-
local bestMode
|
|
206
|
-
for _, inputMode in pairs(self._inputModeList) do
|
|
207
|
-
local enableTime = inputMode:GetLastEnabledTime()
|
|
208
|
-
if enableTime >= bestEnabledTime then
|
|
209
|
-
bestEnabledTime = enableTime
|
|
210
|
-
bestMode = inputMode
|
|
211
|
-
end
|
|
212
|
-
end
|
|
213
|
-
|
|
214
|
-
self._activeMode.Value = bestMode
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
--[=[
|
|
218
|
-
Cleans up the input mode selector.
|
|
219
|
-
|
|
220
|
-
:::info
|
|
221
|
-
This should be called whenever the mode selector is done being used.
|
|
222
|
-
:::
|
|
223
|
-
]=]
|
|
224
|
-
function InputModeSelector:Destroy()
|
|
225
|
-
self._maid:DoCleaning()
|
|
226
|
-
setmetatable(self, nil)
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
return InputModeSelector
|