diff --git a/index.html b/index.html
new file mode 100644
index 00000000..9ef6017f
--- /dev/null
+++ b/index.html
@@ -0,0 +1,289 @@
+
+
+
+
+
+
+
+
+ Ultimate Hacking Keyboard - Agent mockups
+
+
+
+Ultimate Hacking Keyboard – Agent mockups
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/script.js b/script.js
new file mode 100644
index 00000000..36cf76f3
--- /dev/null
+++ b/script.js
@@ -0,0 +1,397 @@
+$(function() {
+ // General configuration for popover contents.
+ var contentContext = {
+ keypress: {
+ layers: [
+ {
+ name: 'None',
+ class: 'layer-key layer-key--disabled',
+ primary: 'btn-primary'
+ },
+ {
+ name: 'Mod',
+ class: 'layer-key layer-key--mod',
+ primary: ''
+ },
+ {
+ name: 'Fn',
+ class: 'layer-key layer-key--fn',
+ primary: ''
+ },
+ {
+ name: 'Mouse',
+ class: 'layer-key layer-key--mouse',
+ primary: ''
+ }
+ ],
+ modifiers: {
+ left: [
+ {
+ name: 'LShift',
+ primary: 'btn-primary'
+ },
+ {
+ name: 'LCtrl',
+ primary: ''
+ },
+ {
+ name: 'LSuper',
+ primary: ''
+ },
+ {
+ name: 'LAlt',
+ primary: 'btn-primary'
+ }
+ ],
+ right: [
+ {
+ name: 'RShift',
+ primary: ''
+ },
+ {
+ name: 'RCtrl',
+ primary: ''
+ },
+ {
+ name: 'RSuper',
+ primary: ''
+ },
+ {
+ name: 'RAlt',
+ primary: ''
+ }
+ ]
+ },
+ scancode: [
+ {
+ groupName: 'Letters',
+ groupValues: [
+ {
+ value: 'A',
+ dataExplanation: '',
+ label: 'A'
+ },
+ {
+ value: 'B',
+ dataExplanation: '',
+ label: 'B'
+ },
+ {
+ value: 'C',
+ dataExplanation: '',
+ label: 'C'
+ }
+ ]
+ },
+ {
+ groupName: 'Numbers',
+ groupValues: [
+ {
+ value: '1',
+ dataExplanation: '',
+ label: '1'
+ },
+ {
+ value: '2',
+ dataExplanation: '',
+ label: '2'
+ },
+ {
+ value: '3',
+ dataExplanation: '',
+ label: '3'
+ }
+ ]
+ },
+ {
+ groupName: 'Punctuation',
+ groupValues: [
+ {
+ value: '.',
+ dataExplanation: 'dot',
+ label: '.'
+ },
+ {
+ value: ',',
+ dataExplanation: 'comma',
+ label: ','
+ },
+ {
+ value: '!',
+ dataExplanation: 'exclamation mark',
+ label: '!'
+ }
+ ]
+ },
+ {
+ groupName: 'Other',
+ groupValues: [
+ {
+ value: 'Tab',
+ dataExplanation: '',
+ label: 'Tab'
+ },
+ {
+ value: 'Enter',
+ dataExplanation: '',
+ label: 'Enter'
+ }
+ ]
+ }
+ ],
+ secondaryRole: [
+ {
+ name: 'None'
+ },
+ {
+ name: 'LShift'
+ },
+ {
+ name: 'LCtrl'
+ },
+ {
+ name: 'LSuper'
+ },
+ {
+ name: 'LAlt'
+ },
+ {
+ name: 'RAlt'
+ },
+ {
+ name: 'RSuper'
+ },
+ {
+ name: 'RCtrl'
+ },
+ {
+ name: 'RShift'
+ },
+ {
+ name: 'Mod'
+ },
+ {
+ name: 'Mouse'
+ },
+ {
+ name: 'Fn'
+ },
+ ]
+ },
+ macro: {
+ macros: [
+ {
+ value: 'Select macro',
+ name: 'Select macro'
+ },
+ {
+ value: 'Latex custom equation',
+ name: 'Latex custom equation'
+ },
+ {
+ value: 'Process shops xml',
+ name: 'Process shops xml'
+ },
+ ]
+ },
+ changeKeymap: {
+ layouts: [
+ {
+ value: 'Select keymap',
+ name: 'Select keymap',
+ dataImage: 'base-layer--blank.svg',
+ abbrev: '',
+ dataAbbrevImage: ''
+ },
+ {
+ value: 'Factory keymap',
+ name: 'Factory keymap',
+ dataImage: 'base-layer.svg',
+ abbrev: 'QWE',
+ dataAbbrevImage: 'segments_qwe.svg'
+ },
+ {
+ value: 'Dvorak',
+ name: 'Dvorak',
+ dataImage: 'base-layer--dvorak.svg',
+ abbrev: 'DVR',
+ dataAbbrevImage: 'segments_dvr.svg'
+ }
+ ]
+ }
+ };
+
+ // Handlebars template for Popover top.
+ var keyEditorTopSource = $('#key-editor-top__source').html();
+ var keyEditorTopTemplate = Handlebars.compile(keyEditorTopSource);
+ var keyEditorTopContext = {
+ buttons: [
+ {
+ type: 'primary',
+ icon: 'fa-keyboard-o',
+ title: 'Keypress',
+ content: 'keypress'
+ },
+ {
+ type: 'default',
+ icon: 'fa-mouse-pointer',
+ title: 'Mouse',
+ content: 'mouse'
+ },
+ {
+ type: 'default',
+ icon: 'fa-play',
+ title: 'Macro',
+ content: 'macro'
+ },
+ {
+ type: 'default',
+ icon: 'fa-keyboard-o',
+ title: 'Change keymap',
+ content: 'changeKeymap'
+ },
+ {
+ type: 'default',
+ icon: 'fa-times',
+ title: 'None',
+ content: 'none'
+ }
+ ]
+ };
+ $('#key-editor-top__target').html(keyEditorTopTemplate(keyEditorTopContext));
+
+ // Handlebars template for Popover bottom.
+ var keyEditorBottomSource = $('#key-editor-bottom__source').html();
+ var keyEditorBottomTemplate = Handlebars.compile(keyEditorBottomSource);
+ var keyEditorBottomContext = {};
+ $('#key-editor-bottom__target').html(keyEditorBottomTemplate(keyEditorBottomContext));
+
+ // Handlebars template for Popover content to be displayed by default.
+ var keyEditorContentSource = $('#key-editor-content__source--keypress').html();
+ var keyEditorContentTemplate = Handlebars.compile(keyEditorContentSource);
+ $('#key-editor-content__target').html(keyEditorContentTemplate(contentContext.keypress));
+
+
+ // ================================
+ // General library initializations.
+ // ================================
+
+ // Init select2.
+ $('select').select2({
+ templateResult: formatState
+ });
+
+ // Init tooltips.
+ $('[data-toggle="tooltip"]').tooltip()
+
+ // Init popover-title tabs.
+ $('li:first', '.popover-title.menu-tabs').addClass('active');
+
+
+ // ===============
+ // Event handlers.
+ // ===============
+
+ $('.popover-menu').on('click', 'button', function() {
+ $('.btn-primary', '.popover-menu').removeClass('btn-primary').addClass('btn-default');
+ $(this).addClass('btn-primary').blur();
+ var tplName = $(this).data('content');
+ var contentSource = $('#key-editor-content__source--' + tplName).html();
+ var contentTemplate = Handlebars.compile(contentSource);
+ $('#key-editor-content__target').html(contentTemplate(contentContext[tplName]));
+ initSelect2items();
+ });
+
+ $('.popover-menu').on('click', 'a.menu-tabs--item', function() {
+ $('.popover-menu.nav-tabs li.active').removeClass('active');
+ $(this).parent('li').addClass('active');
+ var tplName = $(this).data('content');
+ var contentSource = $('#key-editor-content__source--' + tplName).html();
+ var contentTemplate = Handlebars.compile(contentSource);
+ $('#key-editor-content__target').html(contentTemplate(contentContext[tplName]));
+ initSelect2items();
+ });
+
+ $('.modifiers').on('click', 'button', function() {
+ $(this).toggleClass('btn-primary').blur();
+ });
+
+ $('.btn--capture-keystroke').on('click', function(e) {
+ $('.btn--capture-keystroke').toggle();
+ _toggleScancodeForm();
+ });
+
+ $('.layer-action--buttons').on('click', '.layer-key', function(e) {
+ console.log('helllo');
+ $this = $(this);
+ $('.layer-key.btn-primary', '.layer-action--buttons').removeClass('btn-primary');
+ $this.addClass('btn-primary').blur();
+ if ($this.hasClass('layer-key--disabled')) {
+ // Enable all form controls in .global-key-setup
+ $('button, select', '.global-key-setup').prop('disabled', false);
+ $('.global-key-setup').removeClass('disabled');
+ $('.disabled-state--text').hide();
+ }
+ else {
+ // Disable all form controls in .global-key-setup
+ $('button, select', '.global-key-setup').prop('disabled', true);
+ $('.global-key-setup').addClass('disabled');
+ $('.disabled-state--text').show();
+ }
+ });
+});
+
+
+// ==========================
+// Select2 related functions.
+// ==========================
+
+function initSelect2items() {
+ $('select').select2({
+ templateResult: formatState
+ });
+
+ $('select').on('select2:select', function(e) {
+ var selected = $(e.params.data.element);
+ var image = selected.data('image');
+ console.log(e, selected, image);
+ $('img', '.layout-preview').attr('src', 'images/' + image);
+ });
+
+ $('.layout-switcher').on('select2:open', function(e) {
+ $('.layout-preview').css('opacity', '0.1');
+ }).on('select2:close', function(e) {
+ $('.layout-preview').css('opacity', '1');
+ });
+}
+
+function formatState(state) {
+ if (!state.id) { return state.text; }
+ var dataExplanation = $(state.element).data('explanation');
+ var dataAbbrev = $(state.element).data('abbrev');
+ var dataAbbrevImage = $(state.element).data('abbrev-image');
+ var $state = $('' + state.text + '')
+ if (dataExplanation != '' && typeof dataExplanation != 'undefined') {
+ $(' (' + dataExplanation + ')').appendTo($state);
+ }
+ if (dataAbbrevImage != '' && typeof dataAbbrevImage != 'undefined') {
+ $('
')
+ .attr('src', 'images/' + dataAbbrevImage)
+ .attr('class', 'layout-segment-code')
+ .prependTo($state);
+ $state.addClass('keymap-name--wrapper');
+ }
+ return $state;
+}
+
+
+// ===============
+// Misc functions.
+// ===============
+
+function _toggleScancodeForm() {
+ var disabledState = $('.btn--capture-keystroke__stop').is(':visible');
+ $('button', '.modifiers__left, .modifiers__right').prop('disabled', disabledState);
+ $('select.scancode').prop('disabled', disabledState);
+ $('b', '.scancode-options').toggleClass('disabled');
+}
diff --git a/style.css b/style.css
new file mode 100644
index 00000000..d0d89a15
--- /dev/null
+++ b/style.css
@@ -0,0 +1,121 @@
+h1 {
+ margin-bottom: 3rem;
+}
+
+.popover {
+ padding: 0;
+}
+
+.popover-content {
+ padding: 10px 24px;
+}
+
+.popover-title.menu-tabs {
+ padding: .5rem .5rem 0;
+ display: block;
+}
+
+.popover-title.menu-button-group {
+ display: none;
+}
+
+.popover-title.menu-tabs .nav-tabs {
+ position: relative;
+ top: 1px;
+}
+
+.popover.bottom > .arrow:after {
+ border-bottom-color: #f7f7f7;
+}
+
+.popover-actions {
+ padding: 8px 14px;
+ margin: 0;
+ font-size: 14px;
+ background-color: #f7f7f7;
+ border-top: 1px solid #ebebeb;
+ border-radius: 0 0 5px 5px;
+ text-align: right;
+}
+
+.select2-container {
+ z-index: 100000;
+}
+
+.scancode--explanation {
+ color: lightgray;
+ float: right;
+}
+
+.layout-abbreviation {
+ font-weight: bold;
+ color: #FFF;
+ background: #333;
+ padding: 4px 8px;
+ font-family: monospace;
+ margin-right: .5em;
+}
+
+.layout-preview img {
+ max-width: 100%;
+ margin-top: 10px;
+}
+
+.key-editor--none__description p {
+ padding: 2rem 0;
+ margin: 0;
+ text-align: center;
+ font-style: italic;
+ color: #999;
+}
+
+.key-editor--none__description .icon {
+ font-size: 5rem;
+ color: #feefef;
+ position: absolute;
+ z-index: 0;
+ left: 50%;
+ margin-left: -2.5rem;
+ top: 50%;
+ margin-top: -2.5rem;
+}
+
+.select2-item {
+ position: relative;
+ font-size: 1.5rem;
+}
+
+.select2-item.keymap-name--wrapper {
+ padding-left: 50px;
+}
+
+.select2-item .layout-segment-code {
+ height: 2rem;
+ position: absolute;
+ left: 0;
+ top: 50%;
+ margin-top: -1rem;
+}
+
+.preview-wrapper img {
+ max-width: 100%;
+}
+
+.global-key-setup.disabled {
+ opacity: .15;
+}
+
+.global-key-setup.disabled .setting-label,
+.setting-label.disabled {
+ color: #999;
+}
+
+.global-key-setup--wrapper {
+ position: relative;
+}
+
+.global-key-setup--wrapper .disabled-state--text {
+ position: absolute;
+ top: 50%;
+ margin-top: -4rem;
+}