Skip to content

Commit

Permalink
feat(controllers): add "ignore input" setting
Browse files Browse the repository at this point in the history
  • Loading branch information
nvsukhanov committed Sep 1, 2023
1 parent b9e7201 commit afe6682
Show file tree
Hide file tree
Showing 28 changed files with 197 additions and 42 deletions.
10 changes: 7 additions & 3 deletions src/app/controller-profiles/hub/controller-profile-hub.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { Observable, of } from 'rxjs';
import { TranslocoService } from '@ngneat/transloco';
import { ButtonGroupButtonId } from 'rxpoweredup';
import { ControllerType } from '@app/shared';

import { IControllerProfile } from '../i-controller-profile';
import { HubControllerSettings } from '../controller-settings';

export const GREEN_BUTTON_INPUT_ID = 'green-button';

export class ControllerProfileHub implements IControllerProfile<null> {
export class ControllerProfileHub implements IControllerProfile<HubControllerSettings> {
public readonly axisStateL10nKey: string = '';

public readonly buttonStateL10nKey: string = 'controllerProfiles.buttonState';
Expand Down Expand Up @@ -53,7 +55,9 @@ export class ControllerProfileHub implements IControllerProfile<null> {
}
}

public getDefaultSettings(): null {
return null;
public getDefaultSettings(): HubControllerSettings {
return {
controllerType: ControllerType.Hub,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@
>
{{ controllerName$ | ngrxPush }}
</span>
<ng-container *ngIf="controllerSettings.ignoreInput">
<mat-icon *ngIf="controllerSettings.ignoreInput"
[fontIcon]="'do_not_disturb_on'"
[title]="'controller.inputIsIgnored' | transloco"
class="controller-panel__ignore-input-icon"
></mat-icon>
<span class="cdk-visually-hidden">{{ 'controller.inputIsIgnored' | transloco }}</span>
</ng-container>
<span *ngIf="!isConnected"
class="cdk-visually-hidden"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@

.controller-panel {
width: 100%;

&__ignore-input-icon {
margin-left: 10px;
color: var(--app-disabled-color);
}
}

.controller-icon {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<mat-slide-toggle *ngIf="control"
[formControl]="control">
{{ 'controller.ignoreInputControlTitle' | transloco }}
</mat-slide-toggle>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:host {
display: block;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { NgIf } from '@angular/common';
import { TranslocoModule } from '@ngneat/transloco';

@Component({
standalone: true,
selector: 'app-control-ignore-input',
templateUrl: './control-ignore-input.component.html',
styleUrls: [ './control-ignore-input.component.scss' ],
imports: [
MatSlideToggleModule,
ReactiveFormsModule,
NgIf,
TranslocoModule
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ControlIgnoreInputComponent {
@Input() public control?: FormControl<boolean>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './control-ignore-input.component';
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ import { ControllerSettingsModel } from '@app/store';
import { IControllerSettingsRenderer } from './i-controller-settings-renderer';
import { GamepadSettingsComponent } from './gamepad';
import { KeyboardsSettingsComponent } from './keyboard';
import { HubControllerSettingsComponent } from './hub';

type InferControllerSettings<T extends ControllerType> = ControllerSettingsModel & { controllerType: T };

@Injectable({ providedIn: 'root' })
export class ControllerSettingsComponentResolverService {
private renderers: { [k in ControllerType]?: Type<IControllerSettingsRenderer<InferControllerSettings<k>>> } = {
[ControllerType.Keyboard]: KeyboardsSettingsComponent,
[ControllerType.Gamepad]: GamepadSettingsComponent
[ControllerType.Gamepad]: GamepadSettingsComponent,
[ControllerType.Hub]: HubControllerSettingsComponent
};

public resolveComponentFor<T extends ControllerType>(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<ng-container *ngIf="viewModel">
<ng-container *ngFor="let axis of viewModel.axes"
>
<section>
<app-control-ignore-input [control]="viewModel.ignoreInputControl"></app-control-ignore-input>
</section>
<ng-container *ngFor="let axis of viewModel.axes">
<div class="axis-configuration">
<div class="axis-configuration__info">
<h3 class="axis-configuration__info-title">{{ axis.name$ | ngrxPush }}</h3>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { IControllerSettingsRenderer } from '../i-controller-settings-renderer';
import { GamepadAxisSettings, GamepadSettings, GamepadValueTransformService, IControllerProfile } from '../../../../controller-profiles';
import { InputOutputDiagramComponent } from './input-output-diagram';
import { ActiveZoneHumanReadableValuePipe } from './active-zone-human-readable-value.pipe';
import { ControlIgnoreInputComponent } from '../control-ignore-input';

type AxisSettingsViewModel = {
inputId: string;
Expand All @@ -36,12 +37,14 @@ type AxisSettingsViewModel = {

type ViewModel = {
axes: AxisSettingsViewModel[];
ignoreInputControl: FormControl<boolean>;
};

type GamepadSettingsForm = FormGroup<{
controllerId: FormControl<string>;
controllerType: FormControl<ControllerType.Gamepad>;
axisConfigs: FormGroup<{ [k in string]: ToFormGroup<GamepadAxisSettings> }>;
ignoreInput: FormControl<boolean>;
}>;

@Component({
Expand All @@ -64,7 +67,8 @@ type GamepadSettingsForm = FormGroup<{
RangeControlComponent,
TranslocoModule,
ActiveZoneHumanReadableValuePipe,
MatDividerModule
MatDividerModule,
ControlIgnoreInputComponent
],
changeDetection: ChangeDetectionStrategy.OnPush
})
Expand Down Expand Up @@ -114,6 +118,7 @@ export class GamepadSettingsComponent implements IControllerSettingsRenderer<Gam
}),
controllerType: this.formBuilder.control<ControllerType.Gamepad>(ControllerType.Gamepad, { nonNullable: true }),
axisConfigs: this.formBuilder.group<{ [k in string]: ToFormGroup<GamepadAxisSettings> }>({}),
ignoreInput: this.formBuilder.control<boolean>(settings.ignoreInput, { nonNullable: true }),
});

this.canSave$ = this.gamepadSettingsForm.valueChanges.pipe(
Expand All @@ -132,7 +137,8 @@ export class GamepadSettingsComponent implements IControllerSettingsRenderer<Gam
);

const viewModel: ViewModel = {
axes: []
axes: [],
ignoreInputControl: this.gamepadSettingsForm.controls.ignoreInput,
};

for (const [ axisId, axisSettings ] of Object.entries(settings.axisConfigs)) {
Expand Down Expand Up @@ -175,7 +181,7 @@ export class GamepadSettingsComponent implements IControllerSettingsRenderer<Gam
switchMap((profile) => profile.getAxisName$(axisId)),
),
rawValue$,
outputValue$
outputValue$,
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<app-control-ignore-input [control]="ignoreInputControl"></app-control-ignore-input>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:host {
display: block;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { Observable, map } from 'rxjs';
import { FormBuilder, FormControl } from '@angular/forms';
import { HubControllerSettingsModel } from '@app/store';

import { IControllerSettingsRenderer } from '../i-controller-settings-renderer';
import { ControlIgnoreInputComponent } from '../control-ignore-input';

@Component({
standalone: true,
selector: 'app-hub-controller-settings',
templateUrl: './hub-controller-settings.component.html',
styleUrls: [ './hub-controller-settings.component.scss' ],
imports: [
ControlIgnoreInputComponent
],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class HubControllerSettingsComponent implements IControllerSettingsRenderer<HubControllerSettingsModel> {
public readonly canSave$: Observable<boolean>;

public readonly ignoreInputControl: FormControl<boolean>;

private settings?: HubControllerSettingsModel;

constructor(
private readonly formBuilder: FormBuilder,
) {
this.ignoreInputControl = this.formBuilder.control(
false,
{ nonNullable: true }
);
this.canSave$ = this.ignoreInputControl.valueChanges.pipe(
map(() => this.ignoreInputControl.dirty)
);
}

public loadSettings(
settings: HubControllerSettingsModel
): void {
this.settings = settings;
this.ignoreInputControl.setValue(settings.ignoreInput);
}

public readSettings(): HubControllerSettingsModel | undefined {
if (!this.settings) {
return undefined;
}
return {
...this.settings,
ignoreInput: this.ignoreInputControl.value
};
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './hub-controller-settings.component';
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<section *ngIf="formGroup"
class="keyboard-settings-section"
>
<mat-slide-toggle [formControl]="formGroup.controls.captureNonAlphaNumerics">
{{ 'controllerProfiles.keyboard.captureNonAlphaNumerics' | transloco }}
</mat-slide-toggle>
<span class="capture-non-alpha-numerics-hint">
<ng-container *ngIf="formGroup">
<section class="keyboard-settings-section">
<app-control-ignore-input [control]="formGroup.controls.ignoreInput"></app-control-ignore-input>
</section>
<section class="keyboard-settings-section">
<mat-slide-toggle [formControl]="formGroup.controls.captureNonAlphaNumerics">
{{ 'controllerProfiles.keyboard.captureNonAlphaNumerics' | transloco }}
</mat-slide-toggle>
<span class="capture-non-alpha-numerics-hint">
({{ 'controllerProfiles.keyboard.captureNonAlphaNumericsHint' | transloco }})
</span>
</section>
</section>
</ng-container>
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.keyboard-settings-section {
display: flex;
flex-direction: column;
margin-bottom: 10px;
}

.capture-non-alpha-numerics-hint {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ControllerType, ToFormGroup } from '@app/shared';
import { KeyboardSettingsModel } from '@app/store';

import { IControllerSettingsRenderer } from '../i-controller-settings-renderer';
import { ControlIgnoreInputComponent } from '../control-ignore-input';

@Component({
standalone: true,
Expand All @@ -22,7 +23,8 @@ import { IControllerSettingsRenderer } from '../i-controller-settings-renderer';
TranslocoModule,
MatIconModule,
MatTooltipModule,
NgIf
NgIf,
ControlIgnoreInputComponent
],
changeDetection: ChangeDetectionStrategy.OnPush
})
Expand All @@ -46,7 +48,8 @@ export class KeyboardsSettingsComponent implements IControllerSettingsRenderer<K
validators: [ Validators.required ]
}),
controllerType: this.formBuilder.control(ControllerType.Keyboard, { nonNullable: true }) as FormControl<ControllerType.Keyboard>,
captureNonAlphaNumerics: this.formBuilder.control(settings.captureNonAlphaNumerics, { nonNullable: true })
captureNonAlphaNumerics: this.formBuilder.control(settings.captureNonAlphaNumerics, { nonNullable: true }),
ignoreInput: this.formBuilder.control(settings.ignoreInput, { nonNullable: true })
});

this.canSave$ = this.formGroup.valueChanges.pipe(
Expand Down
8 changes: 4 additions & 4 deletions src/app/store/actions/controllers.actions.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { createActionGroup, emptyProps, props } from '@ngrx/store';

import { ControllerSettings } from '../../controller-profiles';
import { GamepadSettings, HubControllerSettings, KeyboardSettings } from '../../controller-profiles';

export const CONTROLLERS_ACTIONS = createActionGroup({
source: 'Controllers',
events: {
'wait for connect': emptyProps(),
'keyboardDiscovered': props<{ profileUid: string; defaultSettings: ControllerSettings }>(),
'keyboardDiscovered': props<{ profileUid: string; defaultSettings: KeyboardSettings }>(),
'keyboardConnected': props<{ profileUid: string }>(),
'gamepadDiscovered': props<{
id: string;
Expand All @@ -16,11 +16,11 @@ export const CONTROLLERS_ACTIONS = createActionGroup({
triggerButtonsIndices: number[];
gamepadApiIndex: number;
gamepadOfTypeIndex: number;
defaultSettings: ControllerSettings;
defaultSettings: GamepadSettings;
}>(),
'gamepadConnected': props<{ id: string; gamepadApiIndex: number; profileUid: string }>(),
'gamepadDisconnected': props<{ id: string }>(),
'hubDiscovered': props<{ profileUid: string; hubId: string; defaultSettings?: ControllerSettings }>(),
'hubDiscovered': props<{ profileUid: string; hubId: string; defaultSettings: HubControllerSettings }>(),
'hubConnected': props<{ hubId: string }>(),
'hubDisconnected': props<{ hubId: string }>()
}
Expand Down
4 changes: 2 additions & 2 deletions src/app/store/controller-profile-factory.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Inject, Injectable } from '@angular/core';
import { TranslocoService } from '@ngneat/transloco';
import { Store } from '@ngrx/store';

import { ControllerSettings, GamepadSettings, IControllerProfile, KeyboardSettings } from '../controller-profiles';
import { ControllerSettings, GamepadSettings, HubControllerSettings, IControllerProfile, KeyboardSettings } from '../controller-profiles';
import { ControllerProfileKeyboardService } from '../controller-profiles/keyboard';
import { ControllerProfileGenericGamepadFactoryService } from '../controller-profiles/gamepad';
import { GamepadProfile } from '../controller-profiles/gamepad-profile';
Expand Down Expand Up @@ -37,7 +37,7 @@ export class ControllerProfileFactoryService { // TODO: refactor, this is a mess

public getHubProfile(
hubId: string,
): IControllerProfile<null> {
): IControllerProfile<HubControllerSettings> {
const profile = this.hubProfileFactory.build(
hubId,
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { concatLatestFrom, createEffect } from '@ngrx/effects';
import { NEVER, Observable, animationFrames, filter, from, map, merge, share, switchMap } from 'rxjs';
import { Action, Store } from '@ngrx/store';
import { inject } from '@angular/core';
import { APP_CONFIG, ControllerInputType, ControllerType, IAppConfig, WINDOW } from '@app/shared';
import { ControllerInputType, ControllerType, WINDOW } from '@app/shared';

import { CONTROLLER_CONNECTION_SELECTORS, CONTROLLER_INPUT_SELECTORS } from '../../../selectors';
import { CONTROLLER_INPUT_ACTIONS } from '../../../actions';
Expand All @@ -12,13 +12,16 @@ import { GamepadValueTransformService } from '../../../../controller-profiles';
function readGamepads(
store: Store,
navigator: Navigator,
config: IAppConfig,
valueTransformer: GamepadValueTransformService
): Observable<Action> {
return store.select(CONTROLLER_CONNECTION_SELECTORS.selectGamepadConnections).pipe(
switchMap((connectedGamepads) => from(connectedGamepads)),
map(({ connection, gamepad, settings }) => {
if (!gamepad || gamepad.controllerType !== ControllerType.Gamepad || !settings || !settings || settings.controllerType !== ControllerType.Gamepad) {
if (!gamepad
|| gamepad.controllerType !== ControllerType.Gamepad
|| settings?.controllerType !== ControllerType.Gamepad
|| settings.ignoreInput
) {
return [ NEVER ];
}
const browserGamepad = navigator.getGamepads()[connection.gamepadIndex] as Gamepad;
Expand Down Expand Up @@ -86,12 +89,11 @@ function createGamepadScheduler(): Observable<unknown> {
export const CAPTURE_GAMEPAD_INPUT = createEffect((
store: Store = inject(Store),
window: Window = inject(WINDOW),
config: IAppConfig = inject(APP_CONFIG),
valueTransformer: GamepadValueTransformService = inject(GamepadValueTransformService)
) => {
return store.select(CONTROLLER_INPUT_SELECTORS.isCapturing).pipe(
switchMap((isCapturing) => isCapturing
? readGamepads(store, window.navigator, config, valueTransformer)
? readGamepads(store, window.navigator, valueTransformer)
: NEVER
)
);
Expand Down
Loading

0 comments on commit afe6682

Please sign in to comment.