procon_bypass_man-web 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|