procon_bypass_man-web 0.1.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.
- checksums.yaml +7 -0
- data/.babelrc +6 -0
- data/.circleci/config.yml +73 -0
- data/.gitignore +12 -0
- data/.rspec +1 -0
- data/.rubocop.yml +26 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +97 -0
- data/LICENSE.txt +21 -0
- data/Procfile +2 -0
- data/README.md +43 -0
- data/Rakefile +4 -0
- data/bin/console +15 -0
- data/bin/pbm_web +7 -0
- data/bin/setup +8 -0
- data/jest.config.ts +194 -0
- data/lib/procon_bypass_man/web.rb +20 -0
- data/lib/procon_bypass_man/web/db.rb +33 -0
- data/lib/procon_bypass_man/web/migration/001_create_settings_table.sql +4 -0
- data/lib/procon_bypass_man/web/models/base_model.rb +47 -0
- data/lib/procon_bypass_man/web/models/setting.rb +22 -0
- data/lib/procon_bypass_man/web/public/bundle.js +2 -0
- data/lib/procon_bypass_man/web/public/bundle.js.LICENSE.txt +57 -0
- data/lib/procon_bypass_man/web/public/index.html +1 -0
- data/lib/procon_bypass_man/web/server.rb +139 -0
- data/lib/procon_bypass_man/web/setting_parser.rb +190 -0
- data/lib/procon_bypass_man/web/storage.rb +25 -0
- data/lib/procon_bypass_man/web/version.rb +7 -0
- data/package.json +48 -0
- data/procon_bypass_man-web.gemspec +36 -0
- data/src/app.tsx +5 -0
- data/src/components/button_setting.tsx +142 -0
- data/src/components/buttons_modal.tsx +110 -0
- data/src/components/buttons_setting.tsx +67 -0
- data/src/components/installable_macros.tsx +58 -0
- data/src/components/installable_modes.tsx +57 -0
- data/src/components/macro_settings.tsx +85 -0
- data/src/components/mode_settings.tsx +62 -0
- data/src/contexts/buttons_setting.ts +2 -0
- data/src/index.html +11 -0
- data/src/lib/button_state.test.ts +110 -0
- data/src/lib/button_state.ts +52 -0
- data/src/lib/button_state_diff.test.ts +123 -0
- data/src/lib/button_state_diff.ts +63 -0
- data/src/lib/buttons_setting_converter.test.ts +185 -0
- data/src/lib/buttons_setting_converter.ts +107 -0
- data/src/lib/http_client.ts +93 -0
- data/src/pages/bpm_page.tsx +92 -0
- data/src/pages/buttons_setting_page.tsx +281 -0
- data/src/pages/global_setting_page.tsx +83 -0
- data/src/pages/home.tsx +17 -0
- data/src/pages/recoding_mode_page.tsx +15 -0
- data/src/pages/top.tsx +107 -0
- data/src/reducers/layer_reducer.ts +120 -0
- data/src/types/button.ts +2 -0
- data/src/types/buttons_setting_type.ts +63 -0
- data/src/types/layer_key.ts +2 -0
- data/src/types/pbm_stats.ts +1 -0
- data/src/types/plugin.ts +43 -0
- data/tmp/.keep +0 -0
- data/tsconfig.json +75 -0
- data/webpack.config.js +56 -0
- data/yarn.lock +6815 -0
- metadata +150 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
/** @jsx jsx */
|
2
|
+
|
3
|
+
import { jsx, css } from '@emotion/react'
|
4
|
+
import React, { useState, useEffect, useContext } from "react";
|
5
|
+
import { ButtonsSettingContext, } from "./../contexts/buttons_setting";
|
6
|
+
import { Plugin, PluginBody, AvailablePlugins } from "../types/plugin";
|
7
|
+
import { installMacroType, uninstallMacroType } from "../reducers/layer_reducer";
|
8
|
+
|
9
|
+
const macroClassNamespaces = AvailablePlugins.map((v) => {
|
10
|
+
return Object.entries(v).map((v) => {
|
11
|
+
const name = v[0];
|
12
|
+
const plugin = v[1];
|
13
|
+
return plugin.macros.map((m) => {
|
14
|
+
return m.class_namespace
|
15
|
+
})
|
16
|
+
})
|
17
|
+
}).flat().flat();
|
18
|
+
|
19
|
+
|
20
|
+
type Props = {
|
21
|
+
classNamespace: string;
|
22
|
+
};
|
23
|
+
export const InstallableMacro = ({ classNamespace }: Props) => {
|
24
|
+
const { layers, layersDispatch } = useContext(ButtonsSettingContext);
|
25
|
+
const isChecked = (name: string) => {
|
26
|
+
return layers.installed_macros[name] || false;
|
27
|
+
}
|
28
|
+
const handleClick = (e: React.ChangeEvent<HTMLInputElement>) => {
|
29
|
+
if(isChecked(classNamespace)) {
|
30
|
+
layersDispatch({ type: uninstallMacroType, payload: { installed_macro: classNamespace }});
|
31
|
+
} else {
|
32
|
+
layersDispatch({ type: installMacroType, payload: { installed_macro: classNamespace }});
|
33
|
+
}
|
34
|
+
}
|
35
|
+
return(
|
36
|
+
<>
|
37
|
+
<input type="checkbox" onChange={handleClick} checked={isChecked(classNamespace)} /> {classNamespace}
|
38
|
+
</>
|
39
|
+
)
|
40
|
+
}
|
41
|
+
|
42
|
+
export const InstallableMacros = () => {
|
43
|
+
return(
|
44
|
+
<>
|
45
|
+
{
|
46
|
+
macroClassNamespaces.map((classNamespace, i) => {
|
47
|
+
return(
|
48
|
+
<div key={i}>
|
49
|
+
<label>
|
50
|
+
<InstallableMacro classNamespace={classNamespace} />
|
51
|
+
</label>
|
52
|
+
</div>
|
53
|
+
);
|
54
|
+
})
|
55
|
+
}
|
56
|
+
</>
|
57
|
+
)
|
58
|
+
}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
/** @jsx jsx */
|
2
|
+
|
3
|
+
import { jsx, css } from '@emotion/react'
|
4
|
+
import React, { useState, useEffect, useContext } from "react";
|
5
|
+
import { ButtonsSettingContext, } from "./../contexts/buttons_setting";
|
6
|
+
import { Plugin, PluginBody, AvailablePlugins } from "../types/plugin";
|
7
|
+
import { installModeType, uninstallModeType } from "../reducers/layer_reducer";
|
8
|
+
|
9
|
+
const modeClassNamespaces = AvailablePlugins.map((v) => {
|
10
|
+
return Object.entries(v).map((v) => {
|
11
|
+
const name = v[0];
|
12
|
+
const plugin = v[1];
|
13
|
+
return plugin.modes.map((m) => {
|
14
|
+
return m.class_namespace
|
15
|
+
})
|
16
|
+
})
|
17
|
+
}).flat().flat();
|
18
|
+
|
19
|
+
type Props = {
|
20
|
+
classNamespace: string;
|
21
|
+
};
|
22
|
+
export const InstallableMode = ({ classNamespace }: Props) => {
|
23
|
+
const { layers, layersDispatch } = useContext(ButtonsSettingContext);
|
24
|
+
const isChecked = (name: string) => {
|
25
|
+
return layers.installed_modes[name] || false;
|
26
|
+
}
|
27
|
+
const handleClick = (e: React.ChangeEvent<HTMLInputElement>) => {
|
28
|
+
if(isChecked(classNamespace)) {
|
29
|
+
layersDispatch({ type: uninstallModeType, payload: { installed_mode: classNamespace }});
|
30
|
+
} else {
|
31
|
+
layersDispatch({ type: installModeType, payload: { installed_mode: classNamespace }});
|
32
|
+
}
|
33
|
+
}
|
34
|
+
return(
|
35
|
+
<div>
|
36
|
+
<input type="checkbox" onChange={handleClick} checked={isChecked(classNamespace)} />{classNamespace}
|
37
|
+
</div>
|
38
|
+
)
|
39
|
+
}
|
40
|
+
|
41
|
+
export const InstallableModes = () => {
|
42
|
+
return(
|
43
|
+
<>
|
44
|
+
{
|
45
|
+
modeClassNamespaces.map((classNamespace, i) => {
|
46
|
+
return(
|
47
|
+
<div key={i}>
|
48
|
+
<label>
|
49
|
+
<InstallableMode classNamespace={classNamespace} />
|
50
|
+
</label>
|
51
|
+
</div>
|
52
|
+
);
|
53
|
+
})
|
54
|
+
}
|
55
|
+
</>
|
56
|
+
)
|
57
|
+
}
|
@@ -0,0 +1,85 @@
|
|
1
|
+
/** @jsx jsx */
|
2
|
+
|
3
|
+
import { jsx, css } from '@emotion/react'
|
4
|
+
import React, { useState, useContext } from "react";
|
5
|
+
import { ButtonsSettingContext } from "./../contexts/buttons_setting";
|
6
|
+
import { LayerKey } from "../types/layer_key";
|
7
|
+
import { Button } from "../types/button";
|
8
|
+
import { Macro, StructMacro } from "../types/buttons_setting_type";
|
9
|
+
import { Plugin, PluginBody, AvailablePlugins, MacroNameMap } from "../types/plugin";
|
10
|
+
import { ButtonsModal } from "./buttons_modal";
|
11
|
+
import { applyMacroType } from "../reducers/layer_reducer";
|
12
|
+
|
13
|
+
type MacroSettingProps = {
|
14
|
+
layerKey: LayerKey;
|
15
|
+
macro: StructMacro;
|
16
|
+
};
|
17
|
+
const MacroSetting = ({ macro, layerKey }: MacroSettingProps) => {
|
18
|
+
const { layersDispatch } = useContext(ButtonsSettingContext);
|
19
|
+
// for modal
|
20
|
+
const [openModal, setOpenModal] = useState(false)
|
21
|
+
const [modalCallbackOnSubmit, setModalCallbackOnSubmit] = useState(undefined as any)
|
22
|
+
const [modalCloseCallback, setModalCloseCallback] = useState(undefined as any)
|
23
|
+
const [modalTitle, setModalTitle] = useState("")
|
24
|
+
const [modalPrefillButtons, setModalPrefillButtons] = useState<Array<Button>>([])
|
25
|
+
|
26
|
+
const setButtonsForModal = (bs: Array<Button>) => {
|
27
|
+
macro.if_pressed = bs;
|
28
|
+
layersDispatch({ type: applyMacroType, payload: { layerKey: layerKey, macro: macro }});
|
29
|
+
}
|
30
|
+
const handleClick = (e: React.ChangeEvent<HTMLInputElement>) => {
|
31
|
+
setOpenModal(true)
|
32
|
+
setModalTitle("発動キーの設定")
|
33
|
+
setModalPrefillButtons(macro.if_pressed);
|
34
|
+
setModalCallbackOnSubmit(() => setButtonsForModal);
|
35
|
+
setModalCloseCallback(() => setOpenModal);
|
36
|
+
}
|
37
|
+
const isEnable = macro.if_pressed.length > 0;
|
38
|
+
|
39
|
+
return(
|
40
|
+
<>
|
41
|
+
<li key={macro.name}>
|
42
|
+
<label>
|
43
|
+
<input type="checkbox" onChange={handleClick} checked={isEnable} />
|
44
|
+
{MacroNameMap[macro.name]}
|
45
|
+
</label>
|
46
|
+
<br />
|
47
|
+
{isEnable && `${macro.if_pressed.join(", ")}で発動`}
|
48
|
+
</li>
|
49
|
+
<div css={css`position: relative;`}>
|
50
|
+
{openModal && <ButtonsModal callbackOnSubmit={modalCallbackOnSubmit} callbackOnClose={modalCloseCallback} title={modalTitle} prefill={macro.if_pressed} positionOnShown={"relative"} />}
|
51
|
+
</div>
|
52
|
+
</>
|
53
|
+
)
|
54
|
+
}
|
55
|
+
|
56
|
+
type MacroSettingsProps = {
|
57
|
+
layerKey: LayerKey;
|
58
|
+
};
|
59
|
+
export const MacroSettings = ({ layerKey }:MacroSettingsProps) => {
|
60
|
+
const { layers } = useContext(ButtonsSettingContext);
|
61
|
+
const macroTable = layers[layerKey].macro as any || {} as any;
|
62
|
+
const macros = Object.keys(MacroNameMap).reduce((acc, macroName: string) => {
|
63
|
+
const ifp = macroTable[macroName as string] as Array<Button> || [] as Array<Button>;
|
64
|
+
if(layers.installed_macros[macroName]) {
|
65
|
+
acc.push({ name: macroName, if_pressed: ifp } as StructMacro);
|
66
|
+
}
|
67
|
+
return acc;
|
68
|
+
}, [] as Array<any>)
|
69
|
+
const hasSomeMacros = macros.length > 0;
|
70
|
+
|
71
|
+
return(
|
72
|
+
<>
|
73
|
+
{
|
74
|
+
hasSomeMacros &&
|
75
|
+
<ul>
|
76
|
+
{macros.map((m) => {
|
77
|
+
return <MacroSetting key={m.name} macro={m} layerKey={layerKey} />
|
78
|
+
}
|
79
|
+
)}
|
80
|
+
</ul>
|
81
|
+
}
|
82
|
+
{!hasSomeMacros && `選択可能なマクロがありません`}
|
83
|
+
</>
|
84
|
+
)
|
85
|
+
}
|
@@ -0,0 +1,62 @@
|
|
1
|
+
/** @jsx jsx */
|
2
|
+
|
3
|
+
import { jsx, css } from '@emotion/react'
|
4
|
+
import React, { useState, useContext } from "react";
|
5
|
+
import { ButtonsSettingContext } from "./../contexts/buttons_setting";
|
6
|
+
import { Plugin, PluginBody, AvailablePlugins, ModeNameMap } from "../types/plugin";
|
7
|
+
import { LayerKey } from "../types/layer_key";
|
8
|
+
import { Button } from "../types/button";
|
9
|
+
import { StructMode, ModeTable } from "../types/buttons_setting_type";
|
10
|
+
import { applyModeType } from "../reducers/layer_reducer";
|
11
|
+
|
12
|
+
type DetailProps = {
|
13
|
+
layerKey: LayerKey;
|
14
|
+
mode: StructMode;
|
15
|
+
};
|
16
|
+
export const ModeSetting = ({ layerKey, mode }: DetailProps) => {
|
17
|
+
const { layersDispatch, layers } = useContext(ButtonsSettingContext);
|
18
|
+
const handleClick = (e: React.ChangeEvent<HTMLInputElement>) => {
|
19
|
+
layersDispatch({ type: applyModeType, payload: { layerKey: layerKey, mode: mode }});
|
20
|
+
}
|
21
|
+
const isChecked = (mode: StructMode) => {
|
22
|
+
return ((layers[layerKey].mode || false) && !!layers[layerKey].mode[mode.name]);
|
23
|
+
}
|
24
|
+
return(
|
25
|
+
<li>
|
26
|
+
<label><input type="radio" onChange={handleClick} checked={isChecked(mode)} />{mode.name}</label>
|
27
|
+
</li>
|
28
|
+
)
|
29
|
+
}
|
30
|
+
|
31
|
+
type ListProps = {
|
32
|
+
layerKey: LayerKey;
|
33
|
+
};
|
34
|
+
export const ModeSettings = ({ layerKey }:ListProps) => {
|
35
|
+
const { layers } = useContext(ButtonsSettingContext);
|
36
|
+
const modeTable: ModeTable = layers[layerKey].mode || {};
|
37
|
+
const modes = Object.keys(ModeNameMap).reduce((acc, modeName: string) => {
|
38
|
+
if(layers.installed_modes[modeName]) {
|
39
|
+
acc.push({ name: modeName } as StructMode);
|
40
|
+
}
|
41
|
+
return acc;
|
42
|
+
}, [] as Array<StructMode>);
|
43
|
+
modes.unshift({ name: "disable" } as StructMode);
|
44
|
+
|
45
|
+
// const hasSomeModes = layers.modes.length > 1;
|
46
|
+
const hasSomeModes = modes.length > 1;
|
47
|
+
|
48
|
+
return(
|
49
|
+
<>
|
50
|
+
{
|
51
|
+
hasSomeModes &&
|
52
|
+
<ul>
|
53
|
+
{modes.map((m) => {
|
54
|
+
return <ModeSetting key={m.name} mode={m} layerKey={layerKey} />
|
55
|
+
}
|
56
|
+
)}
|
57
|
+
</ul>
|
58
|
+
}
|
59
|
+
{!hasSomeModes && `選択可能なモードがありません`}
|
60
|
+
</>
|
61
|
+
)
|
62
|
+
}
|
data/src/index.html
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
import { ButtonState } from "./button_state";
|
2
|
+
|
3
|
+
describe('flip, macro, remapがundefined', () => {
|
4
|
+
it('全部falseを返す', () => {
|
5
|
+
const buttonState = new ButtonState("y");
|
6
|
+
|
7
|
+
expect(buttonState.isDisabledFlip()).toBe(true);
|
8
|
+
expect(buttonState.isAlwaysFlip()).toBe(false);
|
9
|
+
expect(buttonState.isFlipIfPressedSelf()).toBe(false);
|
10
|
+
expect(buttonState.isFlipIfPressedSomeButtons()).toBe(false);
|
11
|
+
expect(buttonState.hasFlipSetting()).toBe(false);
|
12
|
+
expect(buttonState.isRemap()).toBe(false);
|
13
|
+
})
|
14
|
+
});
|
15
|
+
|
16
|
+
describe('flipに値がある時', () => {
|
17
|
+
describe('enableがtrueの時', () => {
|
18
|
+
describe('if_pressedがundefinedの時', () => {
|
19
|
+
it('isAlwaysFlip()がtrueを返す', () => {
|
20
|
+
const buttonState = new ButtonState("y", { if_pressed: undefined, enable: true });
|
21
|
+
expect(buttonState.isDisabledFlip()).toBe(false);
|
22
|
+
expect(buttonState.isAlwaysFlip()).toBe(true);
|
23
|
+
expect(buttonState.isFlipIfPressedSelf()).toBe(false);
|
24
|
+
expect(buttonState.isFlipIfPressedSomeButtons()).toBe(false);
|
25
|
+
expect(buttonState.hasFlipSetting()).toBe(true);
|
26
|
+
expect(buttonState.isRemap()).toBe(false);
|
27
|
+
})
|
28
|
+
})
|
29
|
+
describe('if_pressedが空配列の時', () => {
|
30
|
+
it('isAlwaysFlip()がtrueを返す', () => {
|
31
|
+
const buttonState = new ButtonState("y", { if_pressed: [], enable: true });
|
32
|
+
expect(buttonState.isDisabledFlip()).toBe(false);
|
33
|
+
expect(buttonState.isAlwaysFlip()).toBe(true);
|
34
|
+
expect(buttonState.isFlipIfPressedSelf()).toBe(false);
|
35
|
+
expect(buttonState.isFlipIfPressedSomeButtons()).toBe(false);
|
36
|
+
expect(buttonState.hasFlipSetting()).toBe(true);
|
37
|
+
expect(buttonState.isRemap()).toBe(false);
|
38
|
+
})
|
39
|
+
})
|
40
|
+
describe('if_pressedに2つの値が入っている時', () => {
|
41
|
+
it('isFlipIfPressedSomeButtons()がtrueを返す', () => {
|
42
|
+
const buttonState = new ButtonState("y", { if_pressed: ["l", "zr"], enable: true });
|
43
|
+
expect(buttonState.isDisabledFlip()).toBe(false);
|
44
|
+
expect(buttonState.isAlwaysFlip()).toBe(false);
|
45
|
+
expect(buttonState.isFlipIfPressedSelf()).toBe(false);
|
46
|
+
expect(buttonState.isFlipIfPressedSomeButtons()).toBe(true);
|
47
|
+
expect(buttonState.hasFlipSetting()).toBe(true);
|
48
|
+
expect(buttonState.isRemap()).toBe(false);
|
49
|
+
})
|
50
|
+
})
|
51
|
+
describe('if_pressedに1つの値が入っている時', () => {
|
52
|
+
it('isFlipIfPressedSomeButtons()がtrueを返す', () => {
|
53
|
+
const buttonState = new ButtonState("y", { if_pressed: ["l"], enable: true });
|
54
|
+
expect(buttonState.isDisabledFlip()).toBe(false);
|
55
|
+
expect(buttonState.isAlwaysFlip()).toBe(false);
|
56
|
+
expect(buttonState.isFlipIfPressedSelf()).toBe(false);
|
57
|
+
expect(buttonState.isFlipIfPressedSomeButtons()).toBe(true);
|
58
|
+
expect(buttonState.hasFlipSetting()).toBe(true);
|
59
|
+
expect(buttonState.isRemap()).toBe(false);
|
60
|
+
})
|
61
|
+
})
|
62
|
+
describe('if_pressedにbuttonと同じ1つの値が入っている時', () => {
|
63
|
+
it('isFlipIfPressedSelf()がtrueを返す', () => {
|
64
|
+
const buttonState = new ButtonState("y", { if_pressed: ["y"], enable: true });
|
65
|
+
expect(buttonState.isDisabledFlip()).toBe(false);
|
66
|
+
expect(buttonState.isAlwaysFlip()).toBe(false);
|
67
|
+
expect(buttonState.isFlipIfPressedSelf()).toBe(true);
|
68
|
+
expect(buttonState.isFlipIfPressedSomeButtons()).toBe(false);
|
69
|
+
expect(buttonState.hasFlipSetting()).toBe(true);
|
70
|
+
expect(buttonState.isRemap()).toBe(false);
|
71
|
+
})
|
72
|
+
})
|
73
|
+
})
|
74
|
+
|
75
|
+
describe('enableがfalseの時', () => {
|
76
|
+
it('isDisabledFlip()がfalseを返す', () => {
|
77
|
+
const buttonState = new ButtonState("y", { if_pressed: [], enable: false });
|
78
|
+
expect(buttonState.isDisabledFlip()).toBe(true);
|
79
|
+
expect(buttonState.isAlwaysFlip()).toBe(false);
|
80
|
+
expect(buttonState.isFlipIfPressedSelf()).toBe(false);
|
81
|
+
expect(buttonState.isFlipIfPressedSomeButtons()).toBe(false);
|
82
|
+
expect(buttonState.hasFlipSetting()).toBe(false);
|
83
|
+
expect(buttonState.isRemap()).toBe(false);
|
84
|
+
})
|
85
|
+
})
|
86
|
+
});
|
87
|
+
|
88
|
+
describe('remapに値がある時', () => {
|
89
|
+
describe("flipに無効な値がある", () => {
|
90
|
+
it('isRemap()がtrueを返す', () => {
|
91
|
+
const buttonState = new ButtonState("y", { if_pressed: [], enable: false }, { to: ["y"] });
|
92
|
+
expect(buttonState.isDisabledFlip()).toBe(true);
|
93
|
+
expect(buttonState.isAlwaysFlip()).toBe(false);
|
94
|
+
expect(buttonState.isFlipIfPressedSelf()).toBe(false);
|
95
|
+
expect(buttonState.isFlipIfPressedSomeButtons()).toBe(false);
|
96
|
+
expect(buttonState.hasFlipSetting()).toBe(false);
|
97
|
+
expect(buttonState.isRemap()).toBe(true);
|
98
|
+
})
|
99
|
+
})
|
100
|
+
describe("flipがundefined", () => {
|
101
|
+
it('isRemap()がtrueを返す', () => {
|
102
|
+
const buttonState = new ButtonState("y", undefined, { to: ["y"] });
|
103
|
+
expect(buttonState.isDisabledFlip()).toBe(true);
|
104
|
+
expect(buttonState.isAlwaysFlip()).toBe(false);
|
105
|
+
expect(buttonState.isFlipIfPressedSelf()).toBe(false);
|
106
|
+
expect(buttonState.isFlipIfPressedSomeButtons()).toBe(false);
|
107
|
+
expect(buttonState.hasFlipSetting()).toBe(false);
|
108
|
+
})
|
109
|
+
})
|
110
|
+
})
|
@@ -0,0 +1,52 @@
|
|
1
|
+
import { Button } from "../types/button";
|
2
|
+
import { Flip, Macro, Remap } from "../types/buttons_setting_type";
|
3
|
+
|
4
|
+
export const flip_types = ["disable", "always", "ifPress"] as const;
|
5
|
+
export type FlipType = typeof flip_types[number];
|
6
|
+
|
7
|
+
export class ButtonState {
|
8
|
+
button: Button;
|
9
|
+
flip?: Flip;
|
10
|
+
remap?: Remap;
|
11
|
+
|
12
|
+
constructor(button: Button, flip?: Flip, remap?: Remap) {
|
13
|
+
this.button = button;
|
14
|
+
this.flip = flip;
|
15
|
+
this.remap = remap;
|
16
|
+
};
|
17
|
+
|
18
|
+
isDisabledFlip(): boolean {
|
19
|
+
if(!this.flip && !this.remap) { return true }
|
20
|
+
if(this.remap) { return true }
|
21
|
+
if(!this.flip) { return false }
|
22
|
+
return this.flip && !this.flip?.enable;
|
23
|
+
}
|
24
|
+
|
25
|
+
isAlwaysFlip(): boolean {
|
26
|
+
if(!this.flip && !this.remap) { return false }
|
27
|
+
if(this.isDisabledFlip()) { return false };
|
28
|
+
return !!this.flip && !!this.flip.enable && (this.flip?.if_pressed || []) ?.length === 0;
|
29
|
+
}
|
30
|
+
|
31
|
+
isFlipIfPressedSelf(): boolean {
|
32
|
+
if(!this.flip && !this.remap) { return false }
|
33
|
+
if(this.isDisabledFlip() || this.isAlwaysFlip() || !this.flip || !this.flip.if_pressed) { return false }
|
34
|
+
return this.flip.if_pressed.length === 1 && this.flip.if_pressed[0] === this.button;
|
35
|
+
}
|
36
|
+
|
37
|
+
isFlipIfPressedSomeButtons(): boolean {
|
38
|
+
if(!this.flip) { return false }
|
39
|
+
if(this.isDisabledFlip() || this.isAlwaysFlip() || this.isFlipIfPressedSelf()) { return false }
|
40
|
+
return true;
|
41
|
+
}
|
42
|
+
|
43
|
+
hasFlipSetting(): boolean {
|
44
|
+
return !this.isDisabledFlip();
|
45
|
+
}
|
46
|
+
|
47
|
+
isRemap(): boolean {
|
48
|
+
if(this.hasFlipSetting()) { return false }
|
49
|
+
if(this.remap && this.remap.to?.length > 0) { return true }
|
50
|
+
return false;
|
51
|
+
}
|
52
|
+
}
|