Macro editor (#87)
This commit is contained in:
committed by
József Farkas
parent
8a76da8df5
commit
fbb4a1cc49
2
.gitignore
vendored
2
.gitignore
vendored
@@ -4,3 +4,5 @@ npm-debug.log
|
||||
dist
|
||||
.idea
|
||||
*.iml
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
|
||||
@@ -36,16 +36,19 @@
|
||||
"@angular/common": "2.0.0-rc.6",
|
||||
"@angular/compiler": "2.0.0-rc.6",
|
||||
"@angular/core": "2.0.0-rc.6",
|
||||
"@angular/forms": "2.0.0-rc.6",
|
||||
"@angular/platform-browser": "2.0.0-rc.6",
|
||||
"@angular/platform-browser-dynamic": "2.0.0-rc.6",
|
||||
"@angular/router": "3.0.0-rc.2",
|
||||
"bootstrap": "^3.3.7",
|
||||
"browser-stdout": "^1.3.0",
|
||||
"core-js": "2.4.1",
|
||||
"dragula": "^3.7.1",
|
||||
"font-awesome": "^4.6.3",
|
||||
"handlebars": "^4.0.5",
|
||||
"jquery": "3.1.0",
|
||||
"json-loader": "^0.5.4",
|
||||
"ng2-dragula": "^1.2.0",
|
||||
"ng2-select2": "0.4.2",
|
||||
"rxjs": "5.0.0-beta.11",
|
||||
"select2": "^4.0.3",
|
||||
|
||||
@@ -1,14 +1,24 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { DragulaModule } from 'ng2-dragula/ng2-dragula';
|
||||
import { Select2Component } from 'ng2-select2/ng2-select2';
|
||||
|
||||
import { MainAppComponent, appRoutingProviders, routing } from './main-app';
|
||||
import { ContenteditableDirective } from './directives/contenteditable';
|
||||
|
||||
import { KeymapAddComponent, KeymapComponent } from './components/keymap';
|
||||
import { LayersComponent } from './components/layers';
|
||||
import { LegacyLoaderComponent } from './components/legacy-loader';
|
||||
import { MacroComponent } from './components/macro';
|
||||
import {
|
||||
MacroActionEditorComponent,
|
||||
MacroComponent,
|
||||
MacroDelayTabComponent,
|
||||
MacroItemComponent,
|
||||
MacroKeyTabComponent,
|
||||
MacroMouseTabComponent,
|
||||
MacroTextTabComponent
|
||||
} from './components/macro';
|
||||
import { NotificationComponent } from './components/notification';
|
||||
import { PopoverComponent } from './components/popover';
|
||||
import {
|
||||
@@ -19,7 +29,6 @@ import {
|
||||
MouseTabComponent,
|
||||
NoneTabComponent
|
||||
} from './components/popover/tab';
|
||||
import { MacroItemComponent } from './components/popover/tab/macro';
|
||||
import { CaptureKeystrokeButtonComponent } from './components/popover/widgets/capture-keystroke';
|
||||
import { IconComponent } from './components/popover/widgets/icon';
|
||||
import { SideMenuComponent } from './components/side-menu';
|
||||
@@ -36,6 +45,7 @@ import {
|
||||
} from './components/svg/keys';
|
||||
import { SvgModuleComponent } from './components/svg/module';
|
||||
import { SvgKeyboardWrapComponent } from './components/svg/wrap';
|
||||
import { MainAppComponent, appRoutingProviders, routing } from './main-app';
|
||||
|
||||
import { DataProviderService } from './services/data-provider.service';
|
||||
import { MapperService } from './services/mapper.service';
|
||||
@@ -46,7 +56,6 @@ import {UhkConfigurationService} from './services/uhk-configuration.service';
|
||||
Select2Component,
|
||||
MainAppComponent,
|
||||
KeymapComponent,
|
||||
MacroComponent,
|
||||
LegacyLoaderComponent,
|
||||
NotificationComponent,
|
||||
SvgIconTextKeyComponent,
|
||||
@@ -73,10 +82,19 @@ import {UhkConfigurationService} from './services/uhk-configuration.service';
|
||||
NoneTabComponent,
|
||||
CaptureKeystrokeButtonComponent,
|
||||
IconComponent,
|
||||
MacroItemComponent
|
||||
MacroComponent,
|
||||
MacroItemComponent,
|
||||
MacroActionEditorComponent,
|
||||
MacroDelayTabComponent,
|
||||
MacroKeyTabComponent,
|
||||
MacroMouseTabComponent,
|
||||
MacroTextTabComponent,
|
||||
ContenteditableDirective
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
FormsModule,
|
||||
DragulaModule,
|
||||
routing
|
||||
],
|
||||
providers: [
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
export * from './macro.component';
|
||||
export * from './macro.routes';
|
||||
export * from './macro-item';
|
||||
export * from './macro-action-editor';
|
||||
export * from './macro-action-editor/tab';
|
||||
|
||||
1
src/components/macro/macro-action-editor/index.ts
Normal file
1
src/components/macro/macro-action-editor/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { MacroActionEditorComponent } from './macro-action-editor.component';
|
||||
@@ -0,0 +1,46 @@
|
||||
<div class="action--editor">
|
||||
<div class="row">
|
||||
<div class="col-xs-4 editor__tab-links">
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
<li #macroText [class.active]="activeTab === TabName.Text" (click)="selectTab(TabName.Text)">
|
||||
<a>
|
||||
<i class="fa fa-font"></i>
|
||||
<span>Type text</span>
|
||||
</a>
|
||||
</li>
|
||||
<li #macroKeypress [class.active]="activeTab === TabName.Keypress" (click)="selectTab(TabName.Keypress)">
|
||||
<a>
|
||||
<i class="fa fa-keyboard-o"></i>
|
||||
<span>Key action</span>
|
||||
</a>
|
||||
</li>
|
||||
<li #macroMouse [class.active]="activeTab === TabName.Mouse" (click)="selectTab(TabName.Mouse)">
|
||||
<a>
|
||||
<i class="fa fa-mouse-pointer"></i>
|
||||
<span>Mouse action</span>
|
||||
</a>
|
||||
</li>
|
||||
<li #macroDelay [class.active]="activeTab === TabName.Delay" (click)="selectTab(TabName.Delay)">
|
||||
<a>
|
||||
<i class="fa fa-clock-o"></i>
|
||||
<span>Delay</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-xs-8 editor__tabs" [ngSwitch]="activeTab">
|
||||
<macro-text-tab #tab *ngSwitchCase="TabName.Text" [macroAction]="editableMacroAction"></macro-text-tab>
|
||||
<macro-key-tab #tab *ngSwitchCase="TabName.Keypress" [macroAction]="editableMacroAction"></macro-key-tab>
|
||||
<macro-mouse-tab #tab *ngSwitchCase="TabName.Mouse" [macroAction]="editableMacroAction"></macro-mouse-tab>
|
||||
<macro-delay-tab #tab *ngSwitchCase="TabName.Delay" [macroAction]="editableMacroAction"></macro-delay-tab>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 flex-button-wrapper editor__actions-container">
|
||||
<div class="editor__actions">
|
||||
<button class="btn btn-sm btn-default flex-button" type="button" (click)="onCancelClick()"> Cancel </button>
|
||||
<button class="btn btn-sm btn-primary flex-button" type="button" (click)="onSaveClick()"> Save </button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,80 @@
|
||||
.action--editor {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
border-radius: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.nav {
|
||||
padding-bottom: 1rem;
|
||||
|
||||
li {
|
||||
a {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
|
||||
&.selected {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
z-index: 2;
|
||||
|
||||
a {
|
||||
&.selected {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
height: 0;
|
||||
top: 0;
|
||||
right: -4rem;
|
||||
border-color: transparent transparent transparent #337ab7;
|
||||
border-style: solid;
|
||||
border-width: 2rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.editor {
|
||||
&__tabs,
|
||||
&__tab-links {
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
&__tabs {
|
||||
border-left: 1px solid #ddd;
|
||||
margin-left: -1.6rem;
|
||||
padding-left: 3rem;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
float: right;
|
||||
|
||||
&-container {
|
||||
background: #f5f5f5;
|
||||
border-top: 1px solid #ddd;
|
||||
padding: 1rem 1.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.flex-button-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.flex-button {
|
||||
align-self: flex-end;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
|
||||
|
||||
import {
|
||||
EditableMacroAction,
|
||||
MacroAction,
|
||||
TextMacroAction,
|
||||
macroActionType
|
||||
} from '../../../config-serializer/config-items/macro-action';
|
||||
import { MacroKeyTabComponent } from './tab/macro-key';
|
||||
|
||||
enum TabName {
|
||||
Keypress,
|
||||
Text,
|
||||
Mouse,
|
||||
Delay
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: 'macro-action-editor',
|
||||
template: require('./macro-action-editor.component.html'),
|
||||
styles: [require('./macro-action-editor.component.scss')],
|
||||
host: { 'class': 'macro-action-editor' }
|
||||
})
|
||||
export class MacroActionEditorComponent implements OnInit {
|
||||
@Input() macroAction: MacroAction;
|
||||
|
||||
@Output() save = new EventEmitter<MacroAction>();
|
||||
@Output() cancel = new EventEmitter<void>();
|
||||
|
||||
@ViewChild('tab') selectedTab: any;
|
||||
|
||||
private editableMacroAction: EditableMacroAction;
|
||||
private activeTab: TabName;
|
||||
/* tslint:disable:variable-name: It is an enum type. So it can start with uppercase. */
|
||||
/* tslint:disable:no-unused-variable: It is used in the template. */
|
||||
private TabName = TabName;
|
||||
/* tslint:enable:no-unused-variable */
|
||||
/* tslint:enable:variable-name */
|
||||
|
||||
ngOnInit() {
|
||||
let macroAction: MacroAction = this.macroAction ? this.macroAction : new TextMacroAction();
|
||||
this.editableMacroAction = new EditableMacroAction(macroAction.toJsObject());
|
||||
let tab: TabName = this.getTabName(this.editableMacroAction);
|
||||
this.activeTab = tab;
|
||||
}
|
||||
|
||||
onCancelClick(): void {
|
||||
this.cancel.emit();
|
||||
}
|
||||
|
||||
onSaveClick(): void {
|
||||
try {
|
||||
const action = this.editableMacroAction;
|
||||
if (action.isKeyAction()) {
|
||||
// Could updating the saved keys be done in a better way?
|
||||
const tab = this.selectedTab as MacroKeyTabComponent;
|
||||
action.fromKeyAction(tab.getKeyAction());
|
||||
}
|
||||
this.save.emit(action.toClass());
|
||||
} catch (e) {
|
||||
// TODO: show error dialog
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
selectTab(tab: TabName): void {
|
||||
this.activeTab = tab;
|
||||
this.editableMacroAction.macroActionType = this.getTabMacroActionType(tab);
|
||||
}
|
||||
|
||||
getTabName(action: EditableMacroAction): TabName {
|
||||
switch (action.macroActionType) {
|
||||
// Delay action
|
||||
case macroActionType.DelayMacroAction:
|
||||
return TabName.Delay;
|
||||
// Text action
|
||||
case macroActionType.TextMacroAction:
|
||||
return TabName.Text;
|
||||
// Keypress actions
|
||||
case macroActionType.KeyMacroAction:
|
||||
return TabName.Keypress;
|
||||
// Mouse actions
|
||||
case macroActionType.MouseButtonMacroAction:
|
||||
case macroActionType.MoveMouseMacroAction:
|
||||
case macroActionType.ScrollMouseMacroAction:
|
||||
return TabName.Mouse;
|
||||
default:
|
||||
return TabName.Keypress;
|
||||
}
|
||||
}
|
||||
|
||||
getTabMacroActionType(tab: TabName): string {
|
||||
switch (tab) {
|
||||
case TabName.Delay:
|
||||
return macroActionType.DelayMacroAction;
|
||||
case TabName.Keypress:
|
||||
return macroActionType.KeyMacroAction;
|
||||
case TabName.Mouse:
|
||||
return macroActionType.MouseButtonMacroAction;
|
||||
case TabName.Text:
|
||||
return macroActionType.TextMacroAction;
|
||||
default:
|
||||
throw new Error('Could not get macro action type');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
4
src/components/macro/macro-action-editor/tab/index.ts
Normal file
4
src/components/macro/macro-action-editor/tab/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export { MacroDelayTabComponent } from './macro-delay';
|
||||
export { MacroKeyTabComponent } from './macro-key';
|
||||
export { MacroMouseTabComponent } from './macro-mouse';
|
||||
export { MacroTextTabComponent } from './macro-text';
|
||||
@@ -0,0 +1 @@
|
||||
export { MacroDelayTabComponent } from './macro-delay.component';
|
||||
@@ -0,0 +1,26 @@
|
||||
<div class="macro-delay">
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<h4>Enter delay in seconds</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-4">
|
||||
<input #macroDelayInput
|
||||
type="number"
|
||||
min="0"
|
||||
max="1000"
|
||||
step="0.1"
|
||||
placeholder="Delay amount"
|
||||
class="form-control"
|
||||
[(ngModel)]="delay"
|
||||
(ngModelChange)="setDelay($event)">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row macro-delay__presets">
|
||||
<div class="col-xs-12">
|
||||
<h6>Choose a preset</h6>
|
||||
<button *ngFor="let delay of presets" class="btn btn-sm btn-default"(click)="setDelay(delay)">{{delay}}s</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,16 @@
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.macro-delay {
|
||||
&__presets {
|
||||
margin-top: 1rem;
|
||||
|
||||
button {
|
||||
margin-right: 0.25rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { AfterViewInit, Component, ElementRef, Input, OnInit, Renderer, ViewChild } from '@angular/core';
|
||||
|
||||
import { EditableMacroAction } from '../../../../../config-serializer/config-items/macro-action';
|
||||
|
||||
const INITIAL_DELAY = 0.5; // In seconds
|
||||
|
||||
@Component({
|
||||
selector: 'macro-delay-tab',
|
||||
template: require('./macro-delay.component.html'),
|
||||
styles: [require('./macro-delay.component.scss')],
|
||||
host: { 'class': 'macro__delay' }
|
||||
})
|
||||
export class MacroDelayTabComponent implements AfterViewInit, OnInit {
|
||||
@Input() macroAction: EditableMacroAction;
|
||||
@ViewChild('macroDelayInput') input: ElementRef;
|
||||
private delay: number;
|
||||
/* tslint:disable:no-unused-variable: It is used in the template. */
|
||||
private presets: number[] = [0.3, 0.5, 0.8, 1, 2, 3, 4, 5];
|
||||
/* tslint:enable:no-unused-variable */
|
||||
|
||||
constructor(private renderer: Renderer) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.delay = this.macroAction.delay > 0 ? this.macroAction.delay / 1000 : INITIAL_DELAY;
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.renderer.invokeElementMethod(this.input.nativeElement, 'focus');
|
||||
}
|
||||
|
||||
setDelay(value: number): void {
|
||||
this.delay = value;
|
||||
this.macroAction.delay = this.delay * 1000;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { MacroKeyTabComponent } from './macro-key.component';
|
||||
@@ -0,0 +1,32 @@
|
||||
<div class="col-xs-12 macro-key__container">
|
||||
<div class="col-xs-4 macro-key__types">
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
<li #keyMove [class.active]="activeTab === TabName.Keypress" (click)="selectTab(TabName.Keypress)">
|
||||
<a>
|
||||
<i class="fa fa-hand-pointer-o"></i>
|
||||
<span>Press key</span>
|
||||
</a>
|
||||
</li>
|
||||
<li #keyHold [class.active]="activeTab === TabName.Hold" (click)="selectTab(TabName.Hold)">
|
||||
<a>
|
||||
<i class="fa fa-hand-rock-o"></i>
|
||||
<span>Hold key</span>
|
||||
</a>
|
||||
</li>
|
||||
<li #keyRelease [class.active]="activeTab === TabName.Release" (click)="selectTab(TabName.Release)">
|
||||
<a>
|
||||
<i class="fa fa-hand-paper-o"></i>
|
||||
<span>Release key</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-xs-8 macro-key__action-container">
|
||||
<div class="macro-key__action">
|
||||
<h4 *ngIf="activeTab === TabName.Keypress">Press key</h4>
|
||||
<h4 *ngIf="activeTab === TabName.Hold">Hold key</h4>
|
||||
<h4 *ngIf="activeTab === TabName.Release">Release key</h4>
|
||||
<keypress-tab #keypressTab [defaultKeyAction]="defaultKeyAction" [longPressEnabled]="false"></keypress-tab>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,25 @@
|
||||
.macro-key {
|
||||
&__container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&__types {
|
||||
margin-left: 0;
|
||||
padding: 0 0 1rem;
|
||||
}
|
||||
|
||||
&__action {
|
||||
&-container {
|
||||
margin-top: -1rem;
|
||||
padding-top: 1rem;
|
||||
border-left: 1px solid #ddd;
|
||||
}
|
||||
|
||||
padding-left: 3rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.fa {
|
||||
min-width: 14px;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import { Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||
|
||||
import { KeyAction } from '../../../../../config-serializer/config-items/key-action';
|
||||
import { EditableMacroAction, MacroSubAction } from '../../../../../config-serializer/config-items/macro-action';
|
||||
import { KeypressTabComponent } from '../../../../popover/tab';
|
||||
import { Tab } from '../../../../popover/tab';
|
||||
|
||||
enum TabName {
|
||||
Keypress,
|
||||
Hold,
|
||||
Release
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'macro-key-tab',
|
||||
template: require('./macro-key.component.html'),
|
||||
styles: [
|
||||
require('../../macro-action-editor.component.scss'),
|
||||
require('./macro-key.component.scss')
|
||||
],
|
||||
host: { 'class': 'macro__mouse' }
|
||||
})
|
||||
export class MacroKeyTabComponent implements OnInit {
|
||||
@Input() macroAction: EditableMacroAction;
|
||||
@ViewChild('tab') selectedTab: Tab;
|
||||
@ViewChild('keypressTab') keypressTab: KeypressTabComponent;
|
||||
|
||||
private defaultKeyAction: KeyAction;
|
||||
|
||||
private activeTab: TabName;
|
||||
/* tslint:disable:variable-name: It is an enum type. So it can start with uppercase. */
|
||||
/* tslint:disable:no-unused-variable: It is used in the template. */
|
||||
private TabName = TabName;
|
||||
/* tslint:enable:no-unused-variable */
|
||||
/* tslint:enable:variable-name */
|
||||
|
||||
ngOnInit() {
|
||||
this.defaultKeyAction = this.macroAction.toKeystrokeAction();
|
||||
this.selectTab(this.getTabName(this.macroAction));
|
||||
}
|
||||
|
||||
selectTab(tab: TabName): void {
|
||||
this.activeTab = tab;
|
||||
this.macroAction.action = this.getActionType(tab);
|
||||
}
|
||||
|
||||
getTabName(action: EditableMacroAction): TabName {
|
||||
if (!action.action || action.isOnlyPressAction()) {
|
||||
return TabName.Keypress;
|
||||
} else if (action.isOnlyHoldAction()) {
|
||||
return TabName.Hold;
|
||||
} else if (action.isOnlyReleaseAction()) {
|
||||
return TabName.Release;
|
||||
}
|
||||
}
|
||||
|
||||
getActionType(tab: TabName): MacroSubAction {
|
||||
switch (tab) {
|
||||
case TabName.Keypress:
|
||||
return MacroSubAction.press;
|
||||
case TabName.Hold:
|
||||
return MacroSubAction.hold;
|
||||
case TabName.Release:
|
||||
return MacroSubAction.release;
|
||||
default:
|
||||
throw new Error('Invalid tab type');
|
||||
}
|
||||
}
|
||||
|
||||
getKeyAction(): KeyAction {
|
||||
return this.keypressTab.toKeyAction();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { MacroMouseTabComponent } from './macro-mouse.component';
|
||||
@@ -0,0 +1,77 @@
|
||||
<div class="col-xs-12 macro-mouse__container">
|
||||
<div class="col-xs-4 macro-mouse__types">
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
<li #mouseMove [class.active]="activeTab === TabName.Move" (click)="selectTab(TabName.Move)">
|
||||
<a>
|
||||
<i class="fa fa-arrows"></i>
|
||||
<span>Move pointer</span>
|
||||
</a>
|
||||
</li>
|
||||
<li #mouseScroll [class.active]="activeTab === TabName.Scroll" (click)="selectTab(TabName.Scroll)">
|
||||
<a>
|
||||
<i class="fa fa-arrows-v"></i>
|
||||
<span>Scroll</span>
|
||||
</a>
|
||||
</li>
|
||||
<li #mouseClick [class.active]="activeTab === TabName.Click" (click)="selectTab(TabName.Click)">
|
||||
<a>
|
||||
<i class="fa fa-mouse-pointer"></i>
|
||||
<span>Click button</span>
|
||||
</a>
|
||||
</li>
|
||||
<li #mouseHold [class.active]="activeTab === TabName.Hold" (click)="selectTab(TabName.Hold)">
|
||||
<a>
|
||||
<i class="fa fa-hand-rock-o"></i>
|
||||
<span>Hold button</span>
|
||||
</a>
|
||||
</li>
|
||||
<li #mouseRelease [class.active]="activeTab === TabName.Release" (click)="selectTab(TabName.Release)">
|
||||
<a>
|
||||
<i class="fa fa-hand-paper-o"></i>
|
||||
<span>Release button</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-xs-8 macro-mouse__actions" [ngSwitch]="activeTab">
|
||||
<div #tab *ngSwitchCase="TabName.Move">
|
||||
<h4>Move pointer</h4>
|
||||
<p>Use negative values to move down or left from current position.</p>
|
||||
<div class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label for="move-mouse-x">X</label>
|
||||
<input id="move-mouse-x" type="number" class="form-control" [(ngModel)]="macroAction.moveX"> pixels
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="move-mouse-y">Y</label>
|
||||
<input id="move-mouse-y" type="number" class="form-control" [(ngModel)]="macroAction.moveY"> pixels
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div #tab *ngSwitchCase="TabName.Scroll">
|
||||
<h4>Scroll</h4>
|
||||
<p>Use negative values to move down or left from current position.</p>
|
||||
<div class="form-horizontal">
|
||||
<div class="form-group">
|
||||
<label for="scroll-mouse-x">X</label>
|
||||
<input id="scroll-mouse-x" type="number" class="form-control" [(ngModel)]="macroAction.scrollX"> pixels
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="scroll-mouse-y">Y</label>
|
||||
<input id="scroll-mouse-y" type="number" class="form-control" [(ngModel)]="macroAction.scrollY"> pixels
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div #tab *ngIf="activeTab === TabName.Click || activeTab === TabName.Hold || activeTab === TabName.Release">
|
||||
<h4 *ngIf="activeTab === TabName.Click">Click mouse button</h4>
|
||||
<h4 *ngIf="activeTab === TabName.Hold">Hold mouse button</h4>
|
||||
<h4 *ngIf="activeTab === TabName.Release">Release mouse button</h4>
|
||||
<div class="btn-group macro-mouse__buttons">
|
||||
<button *ngFor="let buttonLabel of buttonLabels; let buttonIndex = index"
|
||||
class="btn btn-default"
|
||||
[class.btn-primary]="hasButton(buttonIndex)"
|
||||
(click)="setMouseClick(buttonIndex)">{{buttonLabel}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,43 @@
|
||||
.macro-mouse {
|
||||
&__container {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&__types {
|
||||
border-right: 1px solid #ddd;
|
||||
border-left: 0;
|
||||
margin-top: -1rem;
|
||||
margin-left: 0;
|
||||
padding: 1rem 0;
|
||||
}
|
||||
|
||||
&__actions {
|
||||
padding-left: 3rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
&__buttons {
|
||||
margin-top: 3rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.fa {
|
||||
min-width: 14px;
|
||||
}
|
||||
|
||||
.form-horizontal {
|
||||
.form-group {
|
||||
margin: 0 0 0.5rem;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: inline-block;
|
||||
width: 60%;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import { Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||
|
||||
import { EditableMacroAction, MacroSubAction, macroActionType } from '../../../../../config-serializer/config-items/macro-action';
|
||||
import { Tab } from '../../../../popover/tab';
|
||||
|
||||
enum TabName {
|
||||
Move,
|
||||
Scroll,
|
||||
Click,
|
||||
Hold,
|
||||
Release
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'macro-mouse-tab',
|
||||
template: require('./macro-mouse.component.html'),
|
||||
styles: [
|
||||
require('../../macro-action-editor.component.scss'),
|
||||
require('./macro-mouse.component.scss')
|
||||
],
|
||||
host: { 'class': 'macro__mouse' }
|
||||
})
|
||||
export class MacroMouseTabComponent implements OnInit {
|
||||
@Input() macroAction: EditableMacroAction;
|
||||
@ViewChild('tab') selectedTab: Tab;
|
||||
|
||||
private activeTab: TabName;
|
||||
private buttonLabels: string[];
|
||||
private selectedButtons: boolean[];
|
||||
/* tslint:disable:variable-name: It is an enum type. So it can start with uppercase. */
|
||||
/* tslint:disable:no-unused-variable: It is used in the template. */
|
||||
private TabName = TabName;
|
||||
/* tslint:enable:no-unused-variable */
|
||||
/* tslint:enable:variable-name */
|
||||
|
||||
constructor() {
|
||||
this.buttonLabels = ['Left', 'Middle', 'Right'];
|
||||
this.selectedButtons = Array(this.buttonLabels.length).fill(false);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
const tabName = this.getTabName(this.macroAction);
|
||||
this.selectTab(tabName);
|
||||
const buttonActions = [TabName.Click, TabName.Hold, TabName.Release];
|
||||
if (buttonActions.includes(this.activeTab)) {
|
||||
this.selectedButtons = this.macroAction.getMouseButtons();
|
||||
}
|
||||
}
|
||||
|
||||
selectTab(tab: TabName): void {
|
||||
this.activeTab = tab;
|
||||
this.macroAction.macroActionType = this.getMacroActionType(tab);
|
||||
if (this.macroAction.macroActionType === macroActionType.MouseButtonMacroAction) {
|
||||
this.macroAction.action = this.getAction(tab);
|
||||
}
|
||||
}
|
||||
|
||||
setMouseClick(index: number): void {
|
||||
this.selectedButtons[index] = !this.selectedButtons[index];
|
||||
this.macroAction.setMouseButtons(this.selectedButtons);
|
||||
}
|
||||
|
||||
hasButton(index: number): boolean {
|
||||
return this.selectedButtons[index];
|
||||
}
|
||||
|
||||
getAction(tab: TabName): MacroSubAction {
|
||||
switch (tab) {
|
||||
case TabName.Click:
|
||||
return MacroSubAction.press;
|
||||
case TabName.Hold:
|
||||
return MacroSubAction.hold;
|
||||
case TabName.Release:
|
||||
return MacroSubAction.release;
|
||||
default:
|
||||
throw new Error('Invalid tab name');
|
||||
}
|
||||
}
|
||||
|
||||
getTabName(action: EditableMacroAction): TabName {
|
||||
if (action.macroActionType === macroActionType.MouseButtonMacroAction) {
|
||||
if (!action.action || action.isOnlyPressAction()) {
|
||||
return TabName.Click;
|
||||
} else if (action.isOnlyPressAction()) {
|
||||
return TabName.Hold;
|
||||
} else if (action.isOnlyReleaseAction()) {
|
||||
return TabName.Release;
|
||||
}
|
||||
} else if (action.macroActionType === macroActionType.MoveMouseMacroAction) {
|
||||
return TabName.Move;
|
||||
} else if (action.macroActionType === macroActionType.ScrollMouseMacroAction) {
|
||||
return TabName.Scroll;
|
||||
}
|
||||
return TabName.Move;
|
||||
}
|
||||
|
||||
getMacroActionType(tab: TabName): string {
|
||||
if (tab === TabName.Click || tab === TabName.Hold || tab === TabName.Release) {
|
||||
return macroActionType.MouseButtonMacroAction;
|
||||
} else if (tab === TabName.Move) {
|
||||
return macroActionType.MoveMouseMacroAction;
|
||||
} else if (tab === TabName.Scroll) {
|
||||
return macroActionType.ScrollMouseMacroAction;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { MacroTextTabComponent } from './macro-text.component';
|
||||
@@ -0,0 +1,5 @@
|
||||
<div>
|
||||
<h4>Type text</h4>
|
||||
<p>Input the text you want to type with this macro action.</p>
|
||||
<textarea #macroTextInput name="macro-text" [(ngModel)]="macroAction.text" class="macro__text-input"></textarea>
|
||||
</div>
|
||||
@@ -0,0 +1,11 @@
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.macro__text-input {
|
||||
width: 100%;
|
||||
min-height: 10rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
ElementRef,
|
||||
Input,
|
||||
Renderer,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
|
||||
import { EditableMacroAction } from '../../../../../config-serializer/config-items/macro-action';
|
||||
|
||||
@Component({
|
||||
selector: 'macro-text-tab',
|
||||
template: require('./macro-text.component.html'),
|
||||
styles: [require('./macro-text.component.scss')],
|
||||
host: { 'class': 'macro__text' }
|
||||
})
|
||||
export class MacroTextTabComponent implements AfterViewInit {
|
||||
@Input() macroAction: EditableMacroAction;
|
||||
@ViewChild('macroTextInput') input: ElementRef;
|
||||
|
||||
constructor(private renderer: Renderer) {}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.renderer.invokeElementMethod(this.input.nativeElement, 'focus');
|
||||
}
|
||||
|
||||
}
|
||||
1
src/components/macro/macro-item/index.ts
Normal file
1
src/components/macro/macro-item/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { MacroItemComponent } from './macro-item.component';
|
||||
15
src/components/macro/macro-item/macro-item.component.html
Normal file
15
src/components/macro/macro-item/macro-item.component.html
Normal file
@@ -0,0 +1,15 @@
|
||||
<div class="list-group-item action--item" [class.is-editing]="editing">
|
||||
<span *ngIf="moveable" class="glyphicon glyphicon-option-vertical action--movable" aria-hidden="true"></span>
|
||||
<icon [name]="iconName"></icon>
|
||||
<div class="action--title" (click)="editAction()">{{ title }}</div>
|
||||
<icon *ngIf="deletable" name="trash" (click)="deleteAction()"></icon>
|
||||
<icon *ngIf="editable" name="pencil" (click)="editAction()"></icon>
|
||||
</div>
|
||||
<div class="list-group-item macro-action-editor__container" *ngIf="editable && editing">
|
||||
<macro-action-editor
|
||||
#macroActionEditor
|
||||
*ngIf="editable && editing"
|
||||
[macroAction]="macroAction"
|
||||
(cancel)="cancelEdit()"
|
||||
(save)="saveEditedAction($event)"></macro-action-editor>
|
||||
</div>
|
||||
53
src/components/macro/macro-item/macro-item.component.scss
Normal file
53
src/components/macro/macro-item/macro-item.component.scss
Normal file
@@ -0,0 +1,53 @@
|
||||
:host {
|
||||
&.macro-item:first-of-type {
|
||||
.list-group-item {
|
||||
border-radius: 4px 4px 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.macro-item:last-of-type {
|
||||
.list-group-item {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.action {
|
||||
&--item {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
border: 0;
|
||||
border-bottom: 1px solid #ddd;
|
||||
|
||||
icon {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
&.is-editing {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
}
|
||||
|
||||
&--movable {
|
||||
&:hover {
|
||||
cursor: move;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.macro-action-editor__container {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
border-radius: 0;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
}
|
||||
}
|
||||
195
src/components/macro/macro-item/macro-item.component.ts
Normal file
195
src/components/macro/macro-item/macro-item.component.ts
Normal file
@@ -0,0 +1,195 @@
|
||||
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
|
||||
|
||||
import { KeyModifiers } from '../../../config-serializer/config-items/KeyModifiers';
|
||||
import {
|
||||
DelayMacroAction,
|
||||
KeyMacroAction,
|
||||
MacroAction,
|
||||
MouseButtonMacroAction,
|
||||
MoveMouseMacroAction,
|
||||
ScrollMouseMacroAction,
|
||||
TextMacroAction
|
||||
} from '../../../config-serializer/config-items/macro-action';
|
||||
|
||||
import { MapperService } from '../../../services/mapper.service';
|
||||
|
||||
@Component({
|
||||
selector: 'macro-item',
|
||||
template: require('./macro-item.component.html'),
|
||||
styles: [require('./macro-item.component.scss')],
|
||||
host: { 'class': 'macro-item' }
|
||||
})
|
||||
export class MacroItemComponent implements OnInit, OnChanges {
|
||||
|
||||
@Input() macroAction: MacroAction;
|
||||
@Input() editable: boolean;
|
||||
@Input() deletable: boolean;
|
||||
@Input() moveable: boolean;
|
||||
|
||||
@Output() save = new EventEmitter<MacroAction>();
|
||||
@Output() cancel = new EventEmitter<void>();
|
||||
@Output() edit = new EventEmitter<void>();
|
||||
@Output() delete = new EventEmitter<void>();
|
||||
|
||||
private title: string;
|
||||
private iconName: string;
|
||||
private editing: boolean;
|
||||
|
||||
constructor(private mapper: MapperService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.updateView();
|
||||
if (!this.macroAction) {
|
||||
this.editing = true;
|
||||
}
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
/* tslint:disable:no-string-literal */
|
||||
if (changes['macroAction']) {
|
||||
/* tslint:enable:no-string-literal */
|
||||
this.updateView();
|
||||
}
|
||||
}
|
||||
|
||||
saveEditedAction(editedAction: MacroAction): void {
|
||||
// @todo save this to keyboard
|
||||
console.log('Saved action', editedAction);
|
||||
this.macroAction = editedAction;
|
||||
this.editing = false;
|
||||
this.updateView();
|
||||
this.save.emit(editedAction);
|
||||
}
|
||||
|
||||
editAction(): void {
|
||||
if (!this.editable) {
|
||||
return;
|
||||
}
|
||||
this.editing = true;
|
||||
this.edit.emit();
|
||||
}
|
||||
|
||||
cancelEdit(): void {
|
||||
this.editing = false;
|
||||
this.cancel.emit();
|
||||
}
|
||||
|
||||
deleteAction(): void {
|
||||
this.delete.emit();
|
||||
}
|
||||
|
||||
private updateView(): void {
|
||||
if (!this.macroAction) {
|
||||
this.title = 'New macro action';
|
||||
} else if (this.macroAction instanceof DelayMacroAction) {
|
||||
// Delay
|
||||
this.iconName = 'clock';
|
||||
let action: DelayMacroAction = this.macroAction as DelayMacroAction;
|
||||
const delay = action.delay > 0 ? action.delay / 1000 : 0;
|
||||
this.title = `Delay of ${delay}s`;
|
||||
} else if (this.macroAction instanceof TextMacroAction) {
|
||||
// Write text
|
||||
let action: TextMacroAction = this.macroAction as TextMacroAction;
|
||||
this.iconName = 'font';
|
||||
this.title = `Write text: ${action.text}`;
|
||||
} else if (this.macroAction instanceof KeyMacroAction) {
|
||||
// Key pressed/held/released
|
||||
const action: KeyMacroAction = this.macroAction as KeyMacroAction;
|
||||
this.setKeyActionContent(action);
|
||||
} else if (this.macroAction instanceof MouseButtonMacroAction) {
|
||||
// Mouse button clicked/held/released
|
||||
const action: MouseButtonMacroAction = this.macroAction as MouseButtonMacroAction;
|
||||
this.setMouseButtonActionContent(action);
|
||||
} else if (this.macroAction instanceof MoveMouseMacroAction || this.macroAction instanceof ScrollMouseMacroAction) {
|
||||
// Mouse moved or scrolled
|
||||
this.setMouseMoveScrollActionContent(this.macroAction);
|
||||
} else {
|
||||
this.title = this.macroAction.constructor.name;
|
||||
}
|
||||
}
|
||||
|
||||
private setKeyActionContent(action: KeyMacroAction): void {
|
||||
if (!action.hasScancode() && !action.hasModifiers()) {
|
||||
this.title = 'Invalid keypress';
|
||||
return;
|
||||
}
|
||||
|
||||
if (action.isPressAction()) {
|
||||
// Press key
|
||||
this.iconName = 'hand-pointer';
|
||||
this.title = 'Press key: ';
|
||||
} else if (action.isHoldAction()) {
|
||||
// Hold key
|
||||
this.iconName = 'hand-rock';
|
||||
this.title = 'Hold key: ';
|
||||
} else if (action.isReleaseAction()) {
|
||||
// Release key
|
||||
this.iconName = 'hand-paper';
|
||||
this.title = 'Release key: ';
|
||||
}
|
||||
|
||||
if (action.hasScancode()) {
|
||||
const scancode: string = this.mapper.scanCodeToText(action.scancode).join(' ');
|
||||
if (scancode) {
|
||||
this.title += scancode;
|
||||
}
|
||||
}
|
||||
|
||||
if (action.hasModifiers()) {
|
||||
// Press/hold/release modifiers
|
||||
for (let i = KeyModifiers.leftCtrl; i !== KeyModifiers.rightGui; i <<= 1) {
|
||||
if (action.isModifierActive(i)) {
|
||||
this.title += ' ' + KeyModifiers[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private setMouseMoveScrollActionContent(action: MacroAction): void {
|
||||
let typedAction: any;
|
||||
if (action instanceof MoveMouseMacroAction) {
|
||||
// Move mouse pointer
|
||||
this.iconName = 'mouse-pointer';
|
||||
this.title = 'Move pointer';
|
||||
typedAction = this.macroAction as MoveMouseMacroAction;
|
||||
} else {
|
||||
// Scroll mouse
|
||||
this.iconName = 'mouse-pointer';
|
||||
this.title = 'Scroll';
|
||||
typedAction = this.macroAction as ScrollMouseMacroAction;
|
||||
}
|
||||
|
||||
let needAnd: boolean;
|
||||
if (Math.abs(typedAction.x) !== 0) {
|
||||
this.title += ` by ${Math.abs(typedAction.x)}px ${typedAction.x > 0 ? 'left' : 'right'}`;
|
||||
needAnd = true;
|
||||
}
|
||||
if (Math.abs(typedAction.y) !== 0) {
|
||||
this.title += ` ${needAnd ? 'and' : 'by'} ${Math.abs(typedAction.y)}px ${typedAction.y > 0 ? 'down' : 'up'}`;
|
||||
}
|
||||
}
|
||||
|
||||
private setMouseButtonActionContent(action: MouseButtonMacroAction): void {
|
||||
// Press/hold/release mouse buttons
|
||||
if (action.isOnlyPressAction()) {
|
||||
this.iconName = 'mouse-pointer';
|
||||
this.title = 'Click mouse button: ';
|
||||
} else if (action.isOnlyHoldAction()) {
|
||||
this.iconName = 'hand-rock';
|
||||
this.title = 'Hold mouse button: ';
|
||||
} else if (action.isOnlyReleaseAction()) {
|
||||
this.iconName = 'hand-paper';
|
||||
this.title = 'Release mouse button: ';
|
||||
}
|
||||
|
||||
const buttonLabels: string[] = ['Left', 'Middle', 'Right'];
|
||||
const selectedButtons: boolean[] = action.getMouseButtons();
|
||||
const selectedButtonLabels: string[] = [];
|
||||
selectedButtons.forEach((isSelected, idx) => {
|
||||
if (isSelected && buttonLabels[idx]) {
|
||||
selectedButtonLabels.push(buttonLabels[idx]);
|
||||
}
|
||||
});
|
||||
this.title += selectedButtonLabels.join(', ');
|
||||
}
|
||||
}
|
||||
@@ -1,74 +1,38 @@
|
||||
<div class="macro--edit main-content__inner">
|
||||
<div class="row">
|
||||
<h1 class="col-xs-12 pane-title">
|
||||
<i class="fa fa-play"></i>
|
||||
<span class="macro__name pane-title__name" contenteditable="true">Macro1</span> <i class="fa"></i>
|
||||
<span class="macro__name pane-title__name"
|
||||
#macroNameInput
|
||||
contenteditable="true"
|
||||
[contenteditableUpdateOnEnter]="true"
|
||||
[(contenteditableModel)]="macro.name"
|
||||
(contenteditableModelChange)="onNameChange()">{{macro.name}}</span>
|
||||
</h1>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div id="listWithHandle" class="list-group col-xs-10 col-xs-offset-1">
|
||||
<div class="list-group-item action--item">
|
||||
<span class="glyphicon glyphicon-option-vertical move-handle" aria-hidden="true"></span>
|
||||
<i class="fa fa-mouse-pointer"></i> Move pointer by 100px leftward
|
||||
<i class="glyphicon glyphicon-pencil action--edit"></i>
|
||||
<i class="glyphicon glyphicon-trash action--trash"></i>
|
||||
</div>
|
||||
<div class="list-group-item macro-settings" style="display: none;">
|
||||
<div class="helper"></div>
|
||||
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut
|
||||
labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
|
||||
dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor
|
||||
sit amet.</p>
|
||||
<div class="row">
|
||||
<div class="col-sm-12 flex-button-wrapper">
|
||||
<button class="btn btn-primary btn-sm pull-right flex-button settings-save">Save</button>
|
||||
<button class="btn btn-default btn-sm pull-right flex-button settings-cancel" style="margin-right: .5em;">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="list-group-item action--item">
|
||||
<span class="glyphicon glyphicon-option-vertical move-handle" aria-hidden="true"></span>
|
||||
<i class="fa fa-square"></i> Press letter A
|
||||
<i class="glyphicon glyphicon-pencil action--edit"></i>
|
||||
<i class="glyphicon glyphicon-trash action--trash"></i>
|
||||
</div>
|
||||
<div class="list-group-item action--item">
|
||||
<span class="glyphicon glyphicon-option-vertical move-handle" aria-hidden="true"></span>
|
||||
<i class="fa fa-square"></i> Press Alt+Tab
|
||||
<i class="glyphicon glyphicon-pencil action--edit"></i>
|
||||
<i class="glyphicon glyphicon-trash action--trash"></i>
|
||||
</div>
|
||||
<div class="list-group-item action--item">
|
||||
<span class="glyphicon glyphicon-option-vertical move-handle" aria-hidden="true"></span>
|
||||
<i class="fa fa-clock-o"></i> Delay of 235ms
|
||||
<i class="glyphicon glyphicon-pencil action--edit"></i>
|
||||
<i class="glyphicon glyphicon-trash action--trash"></i>
|
||||
</div>
|
||||
<div class="list-group-item action--item">
|
||||
<span class="glyphicon glyphicon-option-vertical move-handle" aria-hidden="true"></span>
|
||||
<i class="fa fa-mouse-pointer"></i> Press button 1
|
||||
<i class="glyphicon glyphicon-pencil action--edit"></i>
|
||||
<i class="glyphicon glyphicon-trash action--trash"></i>
|
||||
</div>
|
||||
<div class="list-group-item action--item">
|
||||
<span class="glyphicon glyphicon-option-vertical move-handle" aria-hidden="true"></span>
|
||||
<i class="fa fa-mouse-pointer"></i> Scroll by 150px downward
|
||||
<i class="glyphicon glyphicon-pencil action--edit"></i>
|
||||
<i class="glyphicon glyphicon-trash action--trash"></i>
|
||||
<div class="row list-container">
|
||||
<div class="col-xs-10 col-xs-offset-1 list-group" [dragula]="'macroActions'" [dragulaModel]="macro.macroActions.elements">
|
||||
<div class="macro-actions-container">
|
||||
<macro-item *ngFor="let macroAction of macro.macroActions.elements; let macroActionIndex = index"
|
||||
[macroAction]="macroAction"
|
||||
[editable]="true"
|
||||
[deletable]="true"
|
||||
[moveable]="dragEnabled"
|
||||
(save)="onSaveAction($event, index)"
|
||||
(edit)="onEditAction(macroActionIndex)"
|
||||
(cancel)="onCancelEditAction()"
|
||||
(delete)="onDeleteAction(macroActionIndex)"></macro-item>
|
||||
</div>
|
||||
<div class="list-group add-new__action-container">
|
||||
<div class="list-group-item action--item add-new__action-item no-reorder">
|
||||
<a href="#" class="add-new__action-item--link"><i class="fa fa-plus"></i> Add new action item</a>
|
||||
<a class="add-new__action-item--link" (click)="addAction()"><i class="fa fa-plus"></i> Add new action item</a>
|
||||
</div>
|
||||
<div class="list-group-item new-macro-settings">
|
||||
<div class="list-group-item new-macro-settings" *ngIf="hasChanges">
|
||||
<div class="helper"></div>
|
||||
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut
|
||||
labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo
|
||||
dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor
|
||||
sit amet.</p>
|
||||
<p>Remember to save your changes!</p>
|
||||
<div class="row">
|
||||
<div class="col-sm-12 flex-button-wrapper">
|
||||
<button class="btn btn-primary btn-sm pull-right flex-button settings-save">Save</button>
|
||||
<button class="btn btn-default btn-sm pull-right flex-button settings-cancel" style="margin-right: .5em;">Cancel</button>
|
||||
<button class="btn btn-primary btn-sm pull-right flex-button settings-save" (click)="saveMacro()">Save macro</button>
|
||||
<button class="btn btn-default btn-sm pull-right flex-button settings-cancel" style="margin-right: .5em;" (click)="discardChanges()">Discard changes</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
.list-container {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.main-wrapper {
|
||||
width: 500px;
|
||||
}
|
||||
@@ -6,26 +23,42 @@ h1 {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.action--item {
|
||||
padding-left: 8px;
|
||||
.action {
|
||||
&--edit__form {
|
||||
background-color: #fff;
|
||||
margin-left: -0.5rem;
|
||||
margin-right: -15px;
|
||||
margin-top: 15px;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.action--item.active,
|
||||
.action--item.active:hover {
|
||||
&--item {
|
||||
padding-left: 8px;
|
||||
|
||||
&.active,
|
||||
&.active:hover {
|
||||
background-color: white;
|
||||
font-weight: bold;
|
||||
color: black;
|
||||
border-color: black;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.macro__name {
|
||||
border-bottom: 2px dotted #999;
|
||||
padding: 0 0.5rem;
|
||||
margin: 0 0.25rem;
|
||||
}
|
||||
|
||||
.macro-settings {
|
||||
border: 1px solid black;
|
||||
border-top-color: #999;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.macro-settings .helper {
|
||||
.helper {
|
||||
position: absolute;
|
||||
display: block;
|
||||
height: 13px;
|
||||
@@ -34,44 +67,25 @@ h1 {
|
||||
left: 0;
|
||||
top: -14px;
|
||||
}
|
||||
}
|
||||
|
||||
.action--item.active.callout,
|
||||
.macro-settings.callout {
|
||||
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.macro-actions-container {
|
||||
overflow: auto;
|
||||
margin-bottom: 0;
|
||||
border-radius: 4px 4px 0 0;
|
||||
border: 1px solid #ddd;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.list-group-item .move-handle:hover {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.action--edit {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.action--edit:hover {
|
||||
color: #337ab7;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.action--trash {
|
||||
float: right;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.action--trash:hover {
|
||||
color: #d9534f;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.action--edit__form {
|
||||
background-color: #fff;
|
||||
margin-left: -0.5rem;
|
||||
margin-right: -15px;
|
||||
margin-top: 15px;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.flex-button-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
@@ -81,13 +95,22 @@ h1 {
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.add-new__action-item:hover {
|
||||
.add-new__action-container {
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.add-new__action-item {
|
||||
border-radius: 0 0 4px 4px;
|
||||
border-top: 0;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.add-new__action-item--link,
|
||||
.add-new__action-item--link:active,
|
||||
.add-new__action-item--link:hover {
|
||||
&--link,
|
||||
&--link:active,
|
||||
&--link:hover {
|
||||
text-decoration: none;
|
||||
color: #337ab7;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,116 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, OnDestroy, OnInit, QueryList, ViewChildren } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { Subscription } from 'rxjs/Subscription';
|
||||
|
||||
import { DragulaService } from 'ng2-dragula/ng2-dragula';
|
||||
|
||||
import { Macro } from '../../config-serializer/config-items/Macro';
|
||||
import { MacroAction } from '../../config-serializer/config-items/macro-action';
|
||||
import { MacroItemComponent } from './macro-item/macro-item.component';
|
||||
|
||||
import { UhkConfigurationService } from '../../services/uhk-configuration.service';
|
||||
|
||||
@Component({
|
||||
selector: 'macro',
|
||||
template: require('./macro.component.html'),
|
||||
styles: [require('./macro.component.scss')]
|
||||
styles: [require('./macro.component.scss')],
|
||||
viewProviders: [DragulaService]
|
||||
})
|
||||
export class MacroComponent {
|
||||
export class MacroComponent implements OnInit, OnDestroy {
|
||||
@ViewChildren(MacroItemComponent) macroItems: QueryList<MacroItemComponent>;
|
||||
|
||||
constructor() {
|
||||
private macro: Macro;
|
||||
|
||||
private routeSubscription: Subscription;
|
||||
private hasChanges: boolean = false;
|
||||
private dragEnabled: boolean;
|
||||
|
||||
constructor(
|
||||
private uhkConfigurationService: UhkConfigurationService,
|
||||
private route: ActivatedRoute,
|
||||
private dragulaService: DragulaService
|
||||
) {
|
||||
/* tslint:disable:no-unused-variable: Used by Dragula. */
|
||||
dragulaService.setOptions('macroActions', {
|
||||
moves: function (el: any, container: any, handle: any) {
|
||||
return handle.className.includes('action--movable');
|
||||
}
|
||||
});
|
||||
/* tslint:enable:no-unused-variable */
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.routeSubscription = this.route.params.subscribe((params: { id: string }) => {
|
||||
const id: number = Number(params.id);
|
||||
this.macro = this.getMacro(id);
|
||||
this.dragEnabled = true;
|
||||
this.hasChanges = false;
|
||||
});
|
||||
}
|
||||
|
||||
getMacro(id: number): Macro {
|
||||
const config = this.uhkConfigurationService.getUhkConfiguration();
|
||||
const macro: Macro = config.macros.elements.find(item => item.id === id);
|
||||
if (macro) {
|
||||
// Clone macro for editing
|
||||
return new Macro().fromJsObject(macro.toJsObject());
|
||||
}
|
||||
// @todo replace with notification
|
||||
throw new Error('Macro not found');
|
||||
}
|
||||
|
||||
saveMacro() {
|
||||
// @todo Save macro to keyboard
|
||||
}
|
||||
|
||||
addAction() {
|
||||
this.hideOtherActionEditors(this.macro.macroActions.elements.length);
|
||||
this.macro.macroActions.elements.push(undefined);
|
||||
}
|
||||
|
||||
discardChanges() {
|
||||
const id: number = this.macro.id;
|
||||
this.macro = this.getMacro(id);
|
||||
this.hasChanges = false;
|
||||
}
|
||||
|
||||
hideOtherActionEditors(index: number) {
|
||||
this.macroItems.toArray().forEach((macroItem: MacroItemComponent, idx: number) => {
|
||||
if (idx !== index) {
|
||||
macroItem.cancelEdit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onNameChange() {
|
||||
this.hasChanges = true;
|
||||
}
|
||||
|
||||
onEditAction(index: number) {
|
||||
// Hide other editors when clicking edit button of a macro action
|
||||
this.hideOtherActionEditors(index);
|
||||
this.dragEnabled = false;
|
||||
}
|
||||
|
||||
onCancelEditAction() {
|
||||
this.dragEnabled = true;
|
||||
}
|
||||
|
||||
onSaveAction(macroAction: MacroAction, index: number) {
|
||||
this.dragEnabled = true;
|
||||
this.hasChanges = true;
|
||||
this.macro.macroActions.elements[index] = macroAction;
|
||||
}
|
||||
|
||||
onDeleteAction(index: number) {
|
||||
// @ todo show confirm action dialog
|
||||
this.macro.macroActions.elements.splice(index, 1);
|
||||
this.hasChanges = true;
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.routeSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" [ngSwitch]="activeTab">
|
||||
<keypress-tab #tab *ngSwitchCase="TabName.Keypress" class="popover-content" [defaultKeyAction]="defaultKeyAction"></keypress-tab>
|
||||
<keypress-tab #tab *ngSwitchCase="TabName.Keypress" class="popover-content" [defaultKeyAction]="defaultKeyAction" [longPressEnabled]="true"></keypress-tab>
|
||||
<layer-tab #tab *ngSwitchCase="TabName.Layer" class="popover-content" [defaultKeyAction]="defaultKeyAction"></layer-tab>
|
||||
<mouse-tab #tab *ngSwitchCase="TabName.Mouse" class="popover-content" [defaultKeyAction]="defaultKeyAction"></mouse-tab>
|
||||
<macro-tab #tab *ngSwitchCase="TabName.Macro" class="popover-content" [defaultKeyAction]="defaultKeyAction"></macro-tab>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="long-press-container">
|
||||
<div class="long-press-container" *ngIf="longPressEnabled">
|
||||
<b class="setting-label">Long press action:</b>
|
||||
<select2 #longPressSelect [data]="longPressGroups" [value]="selectedLongPressIndex.toString()" (valueChanged)="onLongpressChange($event)"
|
||||
[width]="140"></select2>
|
||||
|
||||
@@ -13,6 +13,7 @@ import {Tab} from '../tab';
|
||||
})
|
||||
export class KeypressTabComponent implements OnInit, Tab {
|
||||
@Input() defaultKeyAction: KeyAction;
|
||||
@Input() longPressEnabled: boolean;
|
||||
|
||||
private leftModifiers: string[];
|
||||
private rightModifiers: string[];
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
export * from './macro-item.component';
|
||||
export * from './macro-tab.component';
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<icon *ngIf="moveable" name="option-vertical"></icon>
|
||||
<icon [name]="iconName"></icon>
|
||||
<div> {{ title }} </div>
|
||||
<icon *ngIf="deletable" name="trash"></icon>
|
||||
<icon *ngIf="editable" name="pencil"></icon>
|
||||
@@ -1,13 +0,0 @@
|
||||
:host {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
|
||||
icon {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
/// <reference path="../../../../config-serializer/Function.d.ts" />
|
||||
|
||||
import { Component, Input, OnChanges, OnInit } from '@angular/core';
|
||||
|
||||
import {KeyModifiers} from '../../../../config-serializer/config-items/KeyModifiers';
|
||||
import {
|
||||
DelayMacroAction,
|
||||
KeyMacroAction,
|
||||
MacroAction,
|
||||
MoveMouseMacroAction,
|
||||
ScrollMouseMacroAction,
|
||||
TextMacroAction
|
||||
} from '../../../../config-serializer/config-items/macro-action';
|
||||
|
||||
import {MapperService} from '../../../../services/mapper.service';
|
||||
|
||||
@Component({
|
||||
selector: 'macro-item',
|
||||
template: require('./macro-item.component.html'),
|
||||
styles: [require('./macro-item.component.scss')]
|
||||
})
|
||||
export class MacroItemComponent implements OnInit, OnChanges {
|
||||
|
||||
@Input() macroAction: MacroAction;
|
||||
@Input() editable: boolean;
|
||||
@Input() deletable: boolean;
|
||||
@Input() moveable: boolean;
|
||||
|
||||
private iconName: string;
|
||||
private title: string;
|
||||
|
||||
constructor(private mapper: MapperService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.updateView();
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
// TODO: check if macroAction changed
|
||||
this.updateView();
|
||||
}
|
||||
|
||||
private updateView(): void {
|
||||
|
||||
this.title = this.macroAction.constructor.name;
|
||||
if (this.macroAction instanceof MoveMouseMacroAction) {
|
||||
this.iconName = 'mouse-pointer';
|
||||
this.title = 'Move pointer';
|
||||
|
||||
let action: MoveMouseMacroAction = this.macroAction as MoveMouseMacroAction;
|
||||
let needAnd: boolean;
|
||||
if (Math.abs(action.x) > 0) {
|
||||
this.title += ` by ${Math.abs(action.x)}px ${action.x > 0 ? 'left' : 'right'}ward`;
|
||||
needAnd = true;
|
||||
}
|
||||
if (Math.abs(action.y) > 0) {
|
||||
this.title += ` ${needAnd ? 'and' : 'by'} ${Math.abs(action.y)}px ${action.y > 0 ? 'down' : 'up'}ward`;
|
||||
}
|
||||
} else if (this.macroAction instanceof DelayMacroAction) {
|
||||
this.iconName = 'clock';
|
||||
let action: DelayMacroAction = this.macroAction as DelayMacroAction;
|
||||
this.title = `Delay of ${action.delay}ms`;
|
||||
} else if (this.macroAction instanceof TextMacroAction) {
|
||||
let action: TextMacroAction = this.macroAction as TextMacroAction;
|
||||
this.title = `Write text: ${action.text}`;
|
||||
} else if (this.macroAction instanceof ScrollMouseMacroAction) {
|
||||
this.iconName = 'mouse-pointer';
|
||||
this.title = 'Scroll';
|
||||
let action: ScrollMouseMacroAction = this.macroAction as ScrollMouseMacroAction;
|
||||
let needAnd: boolean;
|
||||
if (Math.abs(action.x) > 0) {
|
||||
this.title += ` by ${Math.abs(action.x)}px ${action.x > 0 ? 'left' : 'right'}ward`;
|
||||
needAnd = true;
|
||||
}
|
||||
if (Math.abs(action.y) > 0) {
|
||||
this.title += ` ${needAnd ? 'and' : 'by'} ${Math.abs(action.y)}px ${action.y > 0 ? 'down' : 'up'}ward`;
|
||||
}
|
||||
} else if (this.macroAction instanceof KeyMacroAction) {
|
||||
const keyMacroAction: KeyMacroAction = <KeyMacroAction>this.macroAction;
|
||||
this.title += 'KeyMacroAction: ';
|
||||
if (keyMacroAction.isPressAction()) {
|
||||
this.title = 'Press';
|
||||
} else if (keyMacroAction.isHoldAction()) {
|
||||
this.title = 'Hold';
|
||||
} else {
|
||||
this.title = 'Release';
|
||||
}
|
||||
if (keyMacroAction.hasScancode()) {
|
||||
this.title += ' ' + this.mapper.scanCodeToText(keyMacroAction.scancode).join(' ');
|
||||
}
|
||||
this.iconName = 'square';
|
||||
|
||||
for (let i = KeyModifiers.leftCtrl; i !== KeyModifiers.rightCtrl; i <<= 1) {
|
||||
if (keyMacroAction.isModifierActive(i)) {
|
||||
this.title += ' ' + KeyModifiers[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: finish for all MacroAction
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,10 +2,12 @@
|
||||
<b> Play macro: </b>
|
||||
<select2 [data]="macroOptions" [value]="macroOptions[selectedMacroIndex + 1].id" (valueChanged)="onChange($event)" [width]="'100%'"></select2>
|
||||
</div>
|
||||
<div class="macro-action-container">
|
||||
<div class="macro-action-container" [class.inactive]="selectedMacroIndex === -1">
|
||||
<template [ngIf]="selectedMacroIndex >= 0">
|
||||
<div class="list-group">
|
||||
<macro-item *ngFor="let macroAction of macros[selectedMacroIndex].macroActions.elements"
|
||||
[macroAction]="macroAction">
|
||||
</macro-item>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -25,22 +25,16 @@
|
||||
margin: 20px 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
|
||||
macro-item {
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
margin-bottom: -1px;
|
||||
|
||||
&.inactive {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
macro-item:first-child {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
|
||||
macro-item:last-child {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
.list-group {
|
||||
margin-bottom: 0;
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
|
||||
import {KeyAction, MouseAction, MouseActionParam} from '../../../../config-serializer/config-items/key-action';
|
||||
|
||||
import {Tab} from '../tab';
|
||||
|
||||
@Component({
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
<div [ngSwitch]="name">
|
||||
<span *ngSwitchCase="'option-vertical'" class="glyphicon glyphicon-option-vertical" aria-hidden="true"></span>
|
||||
<i *ngSwitchCase="'square'" class="fa fa-square"></i>
|
||||
<i *ngSwitchCase="'hand-pointer'" class="fa fa-hand-pointer-o"></i>
|
||||
<i *ngSwitchCase="'hand-rock'" class="fa fa-hand-rock-o"></i>
|
||||
<i *ngSwitchCase="'hand-paper'" class="fa fa-hand-paper-o"></i>
|
||||
<i *ngSwitchCase="'mouse-pointer'" class="fa fa-mouse-pointer"></i>
|
||||
<i *ngSwitchCase="'clock'" class="fa fa-clock-o"></i>
|
||||
<i *ngSwitchCase="'font'" class="fa fa-font"></i>
|
||||
<i *ngSwitchCase="'trash'" class="glyphicon glyphicon-trash action--trash"></i>
|
||||
<i *ngSwitchCase="'pencil'" class="glyphicon glyphicon-pencil action--edit"></i>
|
||||
<i *ngSwitchCase="'question-circle'" class ="fa fa-question-circle"></i>
|
||||
|
||||
@@ -2,3 +2,21 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.action {
|
||||
|
||||
&--edit {
|
||||
&:hover {
|
||||
color: #337ab7;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&--trash {
|
||||
&:hover {
|
||||
color: #d9534f;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<li class="sidebar__level-1--item">
|
||||
<div class="sidebar__level-1">
|
||||
<i class="fa fa-play"></i> Macros
|
||||
<a href="#" class="btn btn-default pull-right btn-sm">
|
||||
<a class="btn btn-default pull-right btn-sm" (click)="addMacro()">
|
||||
<i class="fa fa-plus"></i>
|
||||
</a>
|
||||
<i class="fa fa-chevron-up pull-right" (click)="toggleHide($event, 'macro')"></i>
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
import { KeyAction, KeystrokeAction, keyActionType } from '../key-action';
|
||||
import { DelayMacroAction } from './DelayMacroAction';
|
||||
import { KeyMacroAction } from './KeyMacroAction';
|
||||
import { MacroAction, MacroSubAction, macroActionType } from './MacroAction';
|
||||
import { MouseButtonMacroAction } from './MouseButtonMacroAction';
|
||||
import { MoveMouseMacroAction } from './MoveMouseMacroAction';
|
||||
import { ScrollMouseMacroAction } from './ScrollMouseMacroAction';
|
||||
import { TextMacroAction } from './TextMacroAction';
|
||||
|
||||
interface JsObjectEditableMacroAction {
|
||||
macroActionType: string;
|
||||
action?: string;
|
||||
scancode?: number;
|
||||
modifierMask?: number;
|
||||
mouseButtonsMask?: number;
|
||||
x?: number;
|
||||
y?: number;
|
||||
delay?: number;
|
||||
text?: string;
|
||||
}
|
||||
|
||||
export class EditableMacroAction {
|
||||
macroActionType: string;
|
||||
action: MacroSubAction;
|
||||
// Key macro action properties
|
||||
scancode: number;
|
||||
modifierMask: number;
|
||||
// Mouse macro action properties
|
||||
mouseButtonsMask: number;
|
||||
moveX: number;
|
||||
moveY: number;
|
||||
scrollX: number;
|
||||
scrollY: number;
|
||||
// Delay macro action properties
|
||||
delay: number;
|
||||
// Text macro action properties
|
||||
text: string;
|
||||
|
||||
constructor(jsObject?: JsObjectEditableMacroAction) {
|
||||
if (!jsObject) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.macroActionType = jsObject.macroActionType;
|
||||
|
||||
switch (this.macroActionType) {
|
||||
case macroActionType.KeyMacroAction:
|
||||
this.action = MacroSubAction[jsObject.action];
|
||||
this.scancode = jsObject.scancode;
|
||||
this.modifierMask = jsObject.modifierMask;
|
||||
break;
|
||||
case macroActionType.MouseButtonMacroAction:
|
||||
this.action = MacroSubAction[jsObject.action];
|
||||
this.mouseButtonsMask = jsObject.mouseButtonsMask;
|
||||
break;
|
||||
case macroActionType.MoveMouseMacroAction:
|
||||
this.moveX = jsObject.x;
|
||||
this.moveY = jsObject.y;
|
||||
break;
|
||||
case macroActionType.ScrollMouseMacroAction:
|
||||
this.scrollX = jsObject.x;
|
||||
this.scrollY = jsObject.y;
|
||||
break;
|
||||
case macroActionType.TextMacroAction:
|
||||
this.text = jsObject.text;
|
||||
break;
|
||||
case macroActionType.DelayMacroAction:
|
||||
this.delay = jsObject.delay;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
toJsObject(): any {
|
||||
return {
|
||||
macroActionType: this.macroActionType,
|
||||
action: this.action,
|
||||
delay: this.delay,
|
||||
text: this.text,
|
||||
scancode: this.scancode,
|
||||
modifierMask: this.modifierMask,
|
||||
mouseButtonsMask: this.mouseButtonsMask,
|
||||
mouseMove: {
|
||||
x: this.moveX,
|
||||
y: this.moveY
|
||||
},
|
||||
mouseScroll: {
|
||||
x: this.scrollX,
|
||||
y: this.scrollY
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fromKeyAction(keyAction: KeyAction): void {
|
||||
let data = keyAction.toJsObject();
|
||||
this.scancode = data.scancode;
|
||||
this.modifierMask = data.modifierMask;
|
||||
}
|
||||
|
||||
toKeystrokeAction(): KeystrokeAction {
|
||||
let data = this.toJsObject();
|
||||
data.keyActionType = keyActionType.KeystrokeAction;
|
||||
return <KeystrokeAction>(new KeystrokeAction().fromJsObject(data));
|
||||
}
|
||||
|
||||
setMouseButtons(buttonStates: boolean[]): void {
|
||||
let bitmask = 0;
|
||||
for (let i = 0; i < buttonStates.length; i++) {
|
||||
bitmask |= Number(buttonStates[i]) << i;
|
||||
}
|
||||
this.mouseButtonsMask = bitmask;
|
||||
}
|
||||
|
||||
getMouseButtons(): boolean[] {
|
||||
let enabledMouseButtons: boolean[] = [];
|
||||
for (let bitmask = this.mouseButtonsMask; bitmask; bitmask >>>= 1) {
|
||||
enabledMouseButtons.push(Boolean(bitmask & 1));
|
||||
}
|
||||
return enabledMouseButtons;
|
||||
}
|
||||
|
||||
toClass(): MacroAction {
|
||||
switch (this.macroActionType) {
|
||||
// Delay action
|
||||
case macroActionType.DelayMacroAction:
|
||||
return new DelayMacroAction().fromJsObject({
|
||||
macroActionType: this.macroActionType,
|
||||
delay: this.delay
|
||||
});
|
||||
// Text action
|
||||
case macroActionType.TextMacroAction:
|
||||
return new TextMacroAction().fromJsObject({
|
||||
macroActionType: this.macroActionType,
|
||||
text: this.text
|
||||
});
|
||||
// Keypress action
|
||||
case macroActionType.KeyMacroAction:
|
||||
return new KeyMacroAction().fromJsObject({
|
||||
macroActionType: this.macroActionType,
|
||||
action: MacroSubAction[this.action],
|
||||
scancode: this.scancode,
|
||||
modifierMask: this.modifierMask
|
||||
});
|
||||
// Mouse actions
|
||||
case macroActionType.MouseButtonMacroAction:
|
||||
return new MouseButtonMacroAction().fromJsObject({
|
||||
macroActionType: this.macroActionType,
|
||||
action: MacroSubAction[this.action],
|
||||
mouseButtonsMask: this.mouseButtonsMask
|
||||
});
|
||||
case macroActionType.MoveMouseMacroAction:
|
||||
return new MoveMouseMacroAction().fromJsObject({
|
||||
macroActionType: this.macroActionType,
|
||||
x: this.moveX,
|
||||
y: this.moveY
|
||||
});
|
||||
case macroActionType.ScrollMouseMacroAction:
|
||||
return new ScrollMouseMacroAction().fromJsObject({
|
||||
macroActionType: this.macroActionType,
|
||||
x: this.scrollX,
|
||||
y: this.scrollY
|
||||
});
|
||||
default:
|
||||
throw new Error('Macro action type is missing or not implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
isKeyAction(): boolean {
|
||||
return this.macroActionType === macroActionType.KeyMacroAction;
|
||||
}
|
||||
|
||||
isMouseButtonAction(): boolean {
|
||||
return this.macroActionType === macroActionType.MouseButtonMacroAction;
|
||||
}
|
||||
|
||||
isOnlyHoldAction(): boolean {
|
||||
return this.action === MacroSubAction.hold;
|
||||
}
|
||||
|
||||
isOnlyPressAction(): boolean {
|
||||
return this.action === MacroSubAction.press;
|
||||
}
|
||||
|
||||
isOnlyReleaseAction(): boolean {
|
||||
return this.action === MacroSubAction.release;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import {assertUInt8} from '../../assert';
|
||||
import {UhkBuffer} from '../../UhkBuffer';
|
||||
import {MacroAction, MacroActionId, macroActionType} from './MacroAction';
|
||||
|
||||
export class HoldMouseButtonsMacroAction extends MacroAction {
|
||||
|
||||
@assertUInt8
|
||||
mouseButtonsMask: number;
|
||||
|
||||
_fromJsObject(jsObject: any): HoldMouseButtonsMacroAction {
|
||||
this.assertMacroActionType(jsObject);
|
||||
this.mouseButtonsMask = jsObject.mouseButtonsMask;
|
||||
return this;
|
||||
}
|
||||
|
||||
_fromBinary(buffer: UhkBuffer): HoldMouseButtonsMacroAction {
|
||||
this.readAndAssertMacroActionId(buffer);
|
||||
this.mouseButtonsMask = buffer.readUInt8();
|
||||
return this;
|
||||
}
|
||||
|
||||
_toJsObject(): any {
|
||||
return {
|
||||
macroActionType: macroActionType.HoldMouseButtonsMacroAction,
|
||||
mouseButtonsMask: this.mouseButtonsMask
|
||||
};
|
||||
}
|
||||
|
||||
_toBinary(buffer: UhkBuffer) {
|
||||
buffer.writeUInt8(MacroActionId.HoldMouseButtonsMacroAction);
|
||||
buffer.writeUInt8(this.mouseButtonsMask);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<HoldMouseButtonsMacroAction mouseButtonsMask="${this.mouseButtonsMask}">`;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,10 @@
|
||||
import { assertEnum, assertUInt8 } from '../../assert';
|
||||
import { UhkBuffer} from '../../UhkBuffer';
|
||||
import { KeyModifiers } from '../KeyModifiers';
|
||||
import { MacroAction, MacroActionId, macroActionType } from './MacroAction';
|
||||
import { MacroAction, MacroActionId, MacroSubAction, macroActionType } from './MacroAction';
|
||||
|
||||
const NUM_OF_COMBINATIONS = 3; // Cases: scancode, modifer, both
|
||||
|
||||
enum Action {
|
||||
press = 0,
|
||||
hold = 1,
|
||||
release = 2
|
||||
}
|
||||
|
||||
interface JsObjectKeyMacroAction {
|
||||
macroActionType: string;
|
||||
action: string;
|
||||
@@ -20,8 +14,8 @@ interface JsObjectKeyMacroAction {
|
||||
|
||||
export class KeyMacroAction extends MacroAction {
|
||||
|
||||
@assertEnum(Action)
|
||||
action: Action;
|
||||
@assertEnum(MacroSubAction)
|
||||
action: MacroSubAction;
|
||||
|
||||
@assertUInt8
|
||||
scancode: number;
|
||||
@@ -31,7 +25,7 @@ export class KeyMacroAction extends MacroAction {
|
||||
|
||||
_fromJsObject(jsObject: JsObjectKeyMacroAction): KeyMacroAction {
|
||||
this.assertMacroActionType(jsObject);
|
||||
this.action = Action[jsObject.action];
|
||||
this.action = MacroSubAction[jsObject.action];
|
||||
this.scancode = jsObject.scancode;
|
||||
this.modifierMask = jsObject.modifierMask;
|
||||
return this;
|
||||
@@ -54,7 +48,7 @@ export class KeyMacroAction extends MacroAction {
|
||||
_toJsObject(): any {
|
||||
let jsObject: JsObjectKeyMacroAction = {
|
||||
macroActionType: macroActionType.KeyMacroAction,
|
||||
action: Action[this.action]
|
||||
action: MacroSubAction[this.action]
|
||||
};
|
||||
|
||||
if (this.hasScancode()) {
|
||||
@@ -104,14 +98,14 @@ export class KeyMacroAction extends MacroAction {
|
||||
}
|
||||
|
||||
isHoldAction(): boolean {
|
||||
return this.action === Action.hold;
|
||||
return this.action === MacroSubAction.hold;
|
||||
}
|
||||
|
||||
isPressAction(): boolean {
|
||||
return this.action === Action.press;
|
||||
return this.action === MacroSubAction.press;
|
||||
}
|
||||
|
||||
isReleaseAction(): boolean {
|
||||
return this.action === Action.release;
|
||||
return this.action === MacroSubAction.release;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,20 +16,29 @@ export enum MacroActionId {
|
||||
ReleaseKeyMacroAction with scancode and modifiers 8
|
||||
*/
|
||||
LastKeyMacroAction = 8,
|
||||
MouseButtonMacroAction = 9,
|
||||
/*
|
||||
9 - 11 are reserved for MouseButtonMacroAction
|
||||
PressMouseButtonsMacroAction = 9,
|
||||
HoldMouseButtonsMacroAction = 10,
|
||||
ReleaseMouseButtonsMacroAction = 11,
|
||||
*/
|
||||
LastMouseButtonMacroAction = 11,
|
||||
MoveMouseMacroAction = 12,
|
||||
ScrollMouseMacroAction = 13,
|
||||
DelayMacroAction = 14,
|
||||
TextMacroAction = 15
|
||||
}
|
||||
|
||||
export enum MacroSubAction {
|
||||
press = 0,
|
||||
hold = 1,
|
||||
release = 2
|
||||
}
|
||||
|
||||
export let macroActionType = {
|
||||
KeyMacroAction : 'key',
|
||||
PressMouseButtonsMacroAction : 'pressMouseButtons',
|
||||
HoldMouseButtonsMacroAction : 'holdMouseButtons',
|
||||
ReleaseMouseButtonsMacroAction : 'releaseMouseButtons',
|
||||
MouseButtonMacroAction : 'mouseButton',
|
||||
MoveMouseMacroAction : 'moveMouse',
|
||||
ScrollMouseMacroAction : 'scrollMouse',
|
||||
DelayMacroAction : 'delay',
|
||||
@@ -53,8 +62,12 @@ export abstract class MacroAction extends Serializable<MacroAction> {
|
||||
if (readMacroActionId < MacroActionId.KeyMacroAction || readMacroActionId > MacroActionId.LastKeyMacroAction) {
|
||||
throw `Invalid ${classname} first byte: ${readMacroActionId}`;
|
||||
}
|
||||
} else if (macroActionId === MacroActionId.MouseButtonMacroAction) {
|
||||
if (readMacroActionId < MacroActionId.MouseButtonMacroAction ||
|
||||
readMacroActionId > MacroActionId.LastMouseButtonMacroAction) {
|
||||
throw `Invalid ${classname} first byte: ${readMacroActionId}`;
|
||||
}
|
||||
else if (readMacroActionId !== macroActionId) {
|
||||
} else if (readMacroActionId !== macroActionId) {
|
||||
throw `Invalid ${classname} first byte: ${readMacroActionId}`;
|
||||
}
|
||||
return readMacroActionId;
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import {ClassArray} from '../../ClassArray';
|
||||
import {UhkBuffer} from '../../UhkBuffer';
|
||||
import {DelayMacroAction} from './DelayMacroAction';
|
||||
import {HoldMouseButtonsMacroAction} from './HoldMouseButtonsMacroAction';
|
||||
import {KeyMacroAction} from './KeyMacroAction';
|
||||
import {MacroAction, MacroActionId, macroActionType} from './MacroAction';
|
||||
import {MouseButtonMacroAction} from './MouseButtonMacroAction';
|
||||
import {MoveMouseMacroAction} from './MoveMouseMacroAction';
|
||||
import {PressMouseButtonsMacroAction} from './PressMouseButtonsMacroAction';
|
||||
import {ReleaseMouseButtonsMacroAction} from './ReleaseMouseButtonsMacroAction';
|
||||
import {ScrollMouseMacroAction} from './ScrollMouseMacroAction';
|
||||
import {TextMacroAction} from './TextMacroAction';
|
||||
|
||||
@@ -16,12 +14,8 @@ export class MacroActions extends ClassArray<MacroAction> {
|
||||
switch (jsObject.macroActionType) {
|
||||
case macroActionType.KeyMacroAction:
|
||||
return new KeyMacroAction().fromJsObject(jsObject);
|
||||
case macroActionType.PressMouseButtonsMacroAction:
|
||||
return new PressMouseButtonsMacroAction().fromJsObject(jsObject);
|
||||
case macroActionType.HoldMouseButtonsMacroAction:
|
||||
return new HoldMouseButtonsMacroAction().fromJsObject(jsObject);
|
||||
case macroActionType.ReleaseMouseButtonsMacroAction:
|
||||
return new ReleaseMouseButtonsMacroAction().fromJsObject(jsObject);
|
||||
case macroActionType.MouseButtonMacroAction:
|
||||
return new MouseButtonMacroAction().fromJsObject(jsObject);
|
||||
case macroActionType.MoveMouseMacroAction:
|
||||
return new MoveMouseMacroAction().fromJsObject(jsObject);
|
||||
case macroActionType.ScrollMouseMacroAction:
|
||||
@@ -48,12 +42,8 @@ export class MacroActions extends ClassArray<MacroAction> {
|
||||
return new KeyMacroAction().fromBinary(buffer);
|
||||
}
|
||||
switch (macroActionFirstByte) {
|
||||
case MacroActionId.PressMouseButtonsMacroAction:
|
||||
return new PressMouseButtonsMacroAction().fromBinary(buffer);
|
||||
case MacroActionId.HoldMouseButtonsMacroAction:
|
||||
return new HoldMouseButtonsMacroAction().fromBinary(buffer);
|
||||
case MacroActionId.ReleaseMouseButtonsMacroAction:
|
||||
return new ReleaseMouseButtonsMacroAction().fromBinary(buffer);
|
||||
case MacroActionId.MouseButtonMacroAction:
|
||||
return new MouseButtonMacroAction().fromBinary(buffer);
|
||||
case MacroActionId.MoveMouseMacroAction:
|
||||
return new MoveMouseMacroAction().fromBinary(buffer);
|
||||
case MacroActionId.ScrollMouseMacroAction:
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import { assertEnum, assertUInt8 } from '../../assert';
|
||||
import { UhkBuffer } from '../../UhkBuffer';
|
||||
import { MacroAction, MacroActionId, MacroSubAction, macroActionType } from './MacroAction';
|
||||
|
||||
export enum MouseButtons {
|
||||
Left = 1 << 0,
|
||||
Middle = 1 << 1,
|
||||
Right = 1 << 2
|
||||
};
|
||||
|
||||
interface JsObjectMouseButtonMacroAction {
|
||||
macroActionType: string;
|
||||
action: string;
|
||||
mouseButtonsMask?: number;
|
||||
}
|
||||
|
||||
export class MouseButtonMacroAction extends MacroAction {
|
||||
@assertEnum(MacroSubAction)
|
||||
action: MacroSubAction;
|
||||
|
||||
@assertUInt8
|
||||
mouseButtonsMask: number;
|
||||
|
||||
_fromJsObject(jsObject: JsObjectMouseButtonMacroAction): MouseButtonMacroAction {
|
||||
this.assertMacroActionType(jsObject);
|
||||
this.action = MacroSubAction[jsObject.action];
|
||||
this.mouseButtonsMask = jsObject.mouseButtonsMask;
|
||||
return this;
|
||||
}
|
||||
|
||||
_fromBinary(buffer: UhkBuffer): MouseButtonMacroAction {
|
||||
this.readAndAssertMacroActionId(buffer);
|
||||
this.mouseButtonsMask = buffer.readUInt8();
|
||||
return this;
|
||||
}
|
||||
|
||||
_toJsObject(): any {
|
||||
return {
|
||||
macroActionType: macroActionType.MouseButtonMacroAction,
|
||||
action: MacroSubAction[this.action],
|
||||
mouseButtonsMask: this.mouseButtonsMask
|
||||
};
|
||||
}
|
||||
|
||||
_toBinary(buffer: UhkBuffer): void {
|
||||
buffer.writeUInt8(MacroActionId.MouseButtonMacroAction);
|
||||
buffer.writeUInt8(this.mouseButtonsMask);
|
||||
}
|
||||
|
||||
setMouseButtons(buttonStates: boolean[]): void {
|
||||
let bitmask = 0;
|
||||
for (let i = 0; i < buttonStates.length; i++) {
|
||||
bitmask |= Number(buttonStates[i]) << i;
|
||||
}
|
||||
this.mouseButtonsMask = bitmask;
|
||||
}
|
||||
|
||||
getMouseButtons(): boolean[] {
|
||||
let enabledMouseButtons: boolean[] = [];
|
||||
for (let bitmask = this.mouseButtonsMask; bitmask; bitmask >>>= 1) {
|
||||
enabledMouseButtons.push(Boolean(bitmask & 1));
|
||||
}
|
||||
return enabledMouseButtons;
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<MouseButtonMacroAction mouseButtonsMask="${this.mouseButtonsMask}">`;
|
||||
}
|
||||
|
||||
hasButtons(): boolean {
|
||||
return this.mouseButtonsMask !== 0;
|
||||
}
|
||||
|
||||
isOnlyHoldAction(): boolean {
|
||||
return this.action === MacroSubAction.hold;
|
||||
}
|
||||
|
||||
isOnlyPressAction(): boolean {
|
||||
return this.action === MacroSubAction.press;
|
||||
}
|
||||
|
||||
isOnlyReleaseAction(): boolean {
|
||||
return this.action === MacroSubAction.release;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import {assertUInt8} from '../../assert';
|
||||
import {UhkBuffer} from '../../UhkBuffer';
|
||||
import {MacroAction, MacroActionId, macroActionType} from './MacroAction';
|
||||
|
||||
export class PressMouseButtonsMacroAction extends MacroAction {
|
||||
|
||||
@assertUInt8
|
||||
mouseButtonsMask: number;
|
||||
|
||||
_fromJsObject(jsObject: any): PressMouseButtonsMacroAction {
|
||||
this.assertMacroActionType(jsObject);
|
||||
this.mouseButtonsMask = jsObject.mouseButtonsMask;
|
||||
return this;
|
||||
}
|
||||
|
||||
_fromBinary(buffer: UhkBuffer): PressMouseButtonsMacroAction {
|
||||
this.readAndAssertMacroActionId(buffer);
|
||||
this.mouseButtonsMask = buffer.readUInt8();
|
||||
return this;
|
||||
}
|
||||
|
||||
_toJsObject(): any {
|
||||
return {
|
||||
macroActionType: macroActionType.PressMouseButtonsMacroAction,
|
||||
mouseButtonsMask: this.mouseButtonsMask
|
||||
};
|
||||
}
|
||||
|
||||
_toBinary(buffer: UhkBuffer) {
|
||||
buffer.writeUInt8(MacroActionId.PressMouseButtonsMacroAction);
|
||||
buffer.writeUInt8(this.mouseButtonsMask);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<PressMouseButtonsMacroAction mouseButtonsMask="${this.mouseButtonsMask}">`;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import {assertUInt8} from '../../assert';
|
||||
import {UhkBuffer} from '../../UhkBuffer';
|
||||
import {MacroAction, MacroActionId, macroActionType} from './MacroAction';
|
||||
|
||||
export class ReleaseMouseButtonsMacroAction extends MacroAction {
|
||||
|
||||
@assertUInt8
|
||||
mouseButtonsMask: number;
|
||||
|
||||
_fromJsObject(jsObject: any): ReleaseMouseButtonsMacroAction {
|
||||
this.assertMacroActionType(jsObject);
|
||||
this.mouseButtonsMask = jsObject.mouseButtonsMask;
|
||||
return this;
|
||||
}
|
||||
|
||||
_fromBinary(buffer: UhkBuffer): ReleaseMouseButtonsMacroAction {
|
||||
this.readAndAssertMacroActionId(buffer);
|
||||
this.mouseButtonsMask = buffer.readUInt8();
|
||||
return this;
|
||||
}
|
||||
|
||||
_toJsObject(): any {
|
||||
return {
|
||||
macroActionType: macroActionType.ReleaseMouseButtonsMacroAction,
|
||||
mouseButtonsMask: this.mouseButtonsMask
|
||||
};
|
||||
}
|
||||
|
||||
_toBinary(buffer: UhkBuffer) {
|
||||
buffer.writeUInt8(MacroActionId.ReleaseMouseButtonsMacroAction);
|
||||
buffer.writeUInt8(this.mouseButtonsMask);
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
return `<ReleaseMouseButtonsMacroAction mouseButtonsMask="${this.mouseButtonsMask}">`;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
export * from './DelayMacroAction';
|
||||
export * from './HoldMouseButtonsMacroAction';
|
||||
export * from './EditableMacroAction';
|
||||
export * from './KeyMacroAction';
|
||||
export * from './MacroAction';
|
||||
export * from './MacroActions';
|
||||
export * from './MoveMouseMacroAction';
|
||||
export * from './PressMouseButtonsMacroAction';
|
||||
export * from './ReleaseMouseButtonsMacroAction';
|
||||
export * from './MouseButtonMacroAction';
|
||||
export * from './ScrollMouseMacroAction';
|
||||
export * from './TextMacroAction';
|
||||
|
||||
@@ -1015,15 +1015,18 @@
|
||||
"modifierMask": 133
|
||||
},
|
||||
{
|
||||
"macroActionType": "pressMouseButtons",
|
||||
"macroActionType": "mouseButton",
|
||||
"action": "press",
|
||||
"mouseButtonsMask": 9
|
||||
},
|
||||
{
|
||||
"macroActionType": "holdMouseButtons",
|
||||
"macroActionType": "mouseButton",
|
||||
"action": "hold",
|
||||
"mouseButtonsMask": 12
|
||||
},
|
||||
{
|
||||
"macroActionType": "releaseMouseButtons",
|
||||
"macroActionType": "mouseButton",
|
||||
"action": "release",
|
||||
"mouseButtonsMask": 104
|
||||
},
|
||||
{
|
||||
@@ -1058,7 +1061,8 @@
|
||||
"scancode": 111
|
||||
},
|
||||
{
|
||||
"macroActionType": "releaseMouseButtons",
|
||||
"macroActionType": "mouseButton",
|
||||
"action": "release",
|
||||
"mouseButtonsMask": 104
|
||||
},
|
||||
{
|
||||
|
||||
45
src/directives/contenteditable/contenteditable.directive.ts
Normal file
45
src/directives/contenteditable/contenteditable.directive.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import {Directive, ElementRef, EventEmitter, Input, OnChanges, Output, Renderer, SimpleChanges } from '@angular/core';
|
||||
|
||||
const KEY_ENTER = 13;
|
||||
|
||||
@Directive({
|
||||
selector: '[contenteditableModel]',
|
||||
host: {
|
||||
'(blur)': 'onBlur()',
|
||||
'(keypress)': 'onKeypress($event)'
|
||||
}
|
||||
})
|
||||
export class ContenteditableDirective implements OnChanges {
|
||||
@Input('contenteditableModel') model: any;
|
||||
@Input('contenteditableUpdateOnEnter') updateOnEnter: boolean;
|
||||
@Output('contenteditableModelChange') update = new EventEmitter();
|
||||
|
||||
private lastViewModel: any;
|
||||
|
||||
constructor(private elRef: ElementRef, private renderer: Renderer) {}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes[this.lastViewModel]) {
|
||||
this.lastViewModel = this.model;
|
||||
this.refreshView();
|
||||
}
|
||||
}
|
||||
|
||||
onKeypress(event: any) {
|
||||
if (this.updateOnEnter && (event.which === KEY_ENTER)) {
|
||||
// Finish editing when Enter pressed
|
||||
this.renderer.invokeElementMethod(this.elRef.nativeElement, 'blur');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
onBlur() {
|
||||
let value = this.elRef.nativeElement.innerText;
|
||||
this.lastViewModel = value;
|
||||
this.update.emit(value);
|
||||
}
|
||||
|
||||
private refreshView() {
|
||||
this.elRef.nativeElement.innerText = this.model;
|
||||
}
|
||||
}
|
||||
1
src/directives/contenteditable/index.ts
Normal file
1
src/directives/contenteditable/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { ContenteditableDirective } from './contenteditable.directive';
|
||||
@@ -17,7 +17,7 @@ main-app {
|
||||
|
||||
.select2 {
|
||||
&-container {
|
||||
z-index: 100000;
|
||||
z-index: 1100;
|
||||
}
|
||||
|
||||
&-results {
|
||||
@@ -33,7 +33,7 @@ main-app {
|
||||
position: fixed;
|
||||
right: -50px;
|
||||
bottom: 40px;
|
||||
z-index: 999999;
|
||||
z-index: 2000;
|
||||
/* stylelint-disable indentation */
|
||||
-webkit-transform: rotate(-45deg);
|
||||
-moz-transform: rotate(-45deg);
|
||||
|
||||
@@ -167,7 +167,7 @@ ul {
|
||||
position: absolute;
|
||||
top: 2rem;
|
||||
right: 2rem;
|
||||
z-index: 10000;
|
||||
z-index: 2000;
|
||||
background-color: #333;
|
||||
color: #eee;
|
||||
|
||||
@@ -270,7 +270,7 @@ svg.uhk {
|
||||
position: fixed;
|
||||
right: -50px;
|
||||
bottom: 40px;
|
||||
z-index: 999999;
|
||||
z-index: 2000;
|
||||
/* stylelint-disable indentation */
|
||||
-webkit-transform: rotate(-45deg);
|
||||
-moz-transform: rotate(-45deg);
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
}
|
||||
|
||||
.select2-container {
|
||||
z-index: 100000;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.nav-tabs > li > a {
|
||||
|
||||
@@ -86,7 +86,8 @@ export class MapperService {
|
||||
undefined, // 79 Right arrow
|
||||
undefined, // 80 Left arrow
|
||||
undefined, // 81 Down arrow
|
||||
undefined // 82 Up arrow
|
||||
undefined, // 82 Up arrow
|
||||
['Num Lock'] // 83
|
||||
];
|
||||
|
||||
private scanCodeFileName: Map<number, string>;
|
||||
@@ -99,7 +100,7 @@ export class MapperService {
|
||||
}
|
||||
|
||||
public scanCodeToText(scanCode: number): string[] {
|
||||
return this.scanCodeTextMap[scanCode] || [ 'Unkown' ];
|
||||
return this.scanCodeTextMap[scanCode] || [ 'Unknown' ];
|
||||
}
|
||||
|
||||
public scanCodeToSvgImagePath(scanCode: number): string {
|
||||
|
||||
Reference in New Issue
Block a user