Skip to content

Commit e90e454

Browse files
committed
Add macro builder for key combination simulation
- Implemented MacroModal component for creating custom key macros - Support for 2-4 key combinations with visual key selection interface
1 parent 730e6d4 commit e90e454

File tree

4 files changed

+322
-16
lines changed

4 files changed

+322
-16
lines changed

src/renderer/src/components/KeyPicker.vue

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
<ColemakDH v-if="layout === 'colemak-dh'" @key="setKey" />
2020
<Dvorak v-if="layout === 'dvorak'" @key="setKey" />
2121
</div>
22-
<div class="secondary mb-4">
22+
<div v-show="showSecondary" class="secondary mb-4">
2323
<div class="tabs tabs-boxed mt-4">
2424
<a class="tab" :class="{ 'tab-active': category === 'basic' }" @click="category = 'basic'"
2525
>Basic</a
@@ -170,7 +170,7 @@
170170
</template>
171171

172172
<script lang="ts" setup>
173-
import { onMounted, ref } from 'vue'
173+
import { computed, onMounted, ref } from 'vue'
174174
import { keyboardStore } from '../store'
175175
import Qwerty from './picker-layouts/Qwerty.vue'
176176
import Colemak from './picker-layouts/Colemak.vue'
@@ -181,6 +181,12 @@ const layout = ref('qwerty')
181181
const category = ref('basic')
182182
const emit = defineEmits(['setKey'])
183183
184+
const props = defineProps<{
185+
showSecondary?: boolean
186+
}>()
187+
188+
const showSecondary = computed(() => props.showSecondary !== false)
189+
184190
// set the currently selected key to keycode
185191
const setKey = (key: string | number) => {
186192
emit('setKey', String(key))

src/renderer/src/components/KeymapEditor.vue

Lines changed: 86 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@
2525
</div>
2626
<div class="mt-4 flex items-center">
2727
<div class="flex gap-2">
28-
<KeymapLayer v-for="(layer, index) in keyboardStore.keymap" :layer="layer" :index="index" />
28+
<KeymapLayer
29+
v-for="(layer, index) in keyboardStore.keymap"
30+
:key="index"
31+
:layer="layer"
32+
:index="index"
33+
/>
2934
</div>
3035
</div>
3136
</div>
@@ -45,17 +50,14 @@
4550
</p>
4651
<div class="flex gap-2">
4752
<select
53+
v-if="selectedKeys.size > 0"
4854
v-model="keycodeModeForSelection"
4955
class="select select-bordered select-sm"
5056
@change="switchedKeyCodeType"
5157
>
52-
<!-- simple will just inline the keycode -->
53-
<option value="simple">Simple</option>
54-
<!-- other options will create a separately linked keycode -->
55-
<option value="string">String</option>
56-
<option value="macro">Macro</option>
57-
<option value="tapdance">Tap Dance</option>
58-
<option value="custom">Custom</option>
58+
<option v-for="option in keycodeModeOptions" :key="option.value" :value="option.value">
59+
{{ option.label }}
60+
</option>
5961
</select>
6062
<div class="flex-grow">
6163
<input
@@ -65,6 +67,21 @@
6567
class="input input-bordered input-sm w-full"
6668
/>
6769
</div>
70+
<button
71+
v-if="selectedKeys.size > 0 && keycodeModeForSelection === 'macro'"
72+
class="btn btn-primary btn-sm"
73+
@click="openMacroModal"
74+
>
75+
Custom Macro
76+
</button>
77+
<a
78+
v-if="selectedKeys.size > 0 && keycodeModeForSelection === 'macro'"
79+
class="btn btn-sm"
80+
href="https://github.com/KMKfw/kmk_firmware/blob/main/docs/en/macros.md"
81+
target="_blank"
82+
>
83+
Guide
84+
</a>
6885
</div>
6986
<div v-if="keycodeModeForSelection === 'custom'" class="p-2 text-sm italic">
7087
<p>
@@ -73,22 +90,49 @@
7390
</p>
7491
</div>
7592
</div>
76-
<KeyPicker @setKey="setKey"></KeyPicker>
93+
<KeyPicker :show-secondary="true" @set-key="setKey"></KeyPicker>
94+
95+
<!-- Macro Modal -->
96+
<MacroModal
97+
:is-open="macroModal.isOpen"
98+
:initial-macro-code="macroModal.initialCode"
99+
@close="closeMacroModal"
100+
@apply="applyMacroCode"
101+
/>
77102
</template>
78103

79104
<script lang="ts" setup>
80105
import { keyboardStore, selectedKeys, selectedLayer, userSettings } from '../store'
81106
import KeyboardLayout from './KeyboardLayout.vue'
82107
import KeyPicker from './KeyPicker.vue'
108+
import MacroModal from './MacroModal.vue'
83109
import { cleanupKeymap, selectNextKey } from '../helpers'
84-
import { computed, ref } from 'vue'
110+
import { computed, ref, watch } from 'vue'
85111
import KeymapLayer from './KeymapLayer.vue'
86112
87113
selectedKeys.value.clear()
88114
89-
const keycodeModeForSelection = ref<
90-
'simple' | 'combo' | 'macro' | 'custom' | 'tapdance' | 'string'
91-
>('simple')
115+
type KeycodeMode = 'simple' | 'combo' | 'macro' | 'custom' | 'tapdance' | 'string'
116+
117+
const keycodeModeForSelection = ref<KeycodeMode>('simple')
118+
119+
const keycodeModeOptions: { value: KeycodeMode; label: string }[] = [
120+
{ value: 'simple', label: 'Simple' },
121+
{ value: 'string', label: 'String' },
122+
{ value: 'macro', label: 'Macro' },
123+
{ value: 'tapdance', label: 'Tap Dance' },
124+
{ value: 'custom', label: 'Custom' }
125+
]
126+
127+
const detectKeycodeType = (keycode: string): KeycodeMode => {
128+
if (!keycode || keycode === 'No key selected' || keycode === '') return 'simple'
129+
if (keycode.includes('KC.MACRO("') || keycode.includes("KC.MACRO('")) return 'string'
130+
if (keycode.includes('KC.MACRO(')) return 'macro'
131+
if (keycode.includes('KC.TD(')) return 'tapdance'
132+
if (keycode.includes('customkeys.')) return 'custom'
133+
if (keycode.includes('KC.COMBO(')) return 'combo'
134+
return 'simple'
135+
}
92136
const setKey = (keyCode: string) => {
93137
selectedKeys.value.forEach((index) => {
94138
keyboardStore.keys[index].setOnKeymap(keyCode)
@@ -173,6 +217,24 @@ const toggleSettings = () => {
173217
settingsOpen.value = !settingsOpen.value
174218
}
175219
220+
const macroModal = ref({
221+
isOpen: false,
222+
initialCode: ''
223+
})
224+
225+
const openMacroModal = () => {
226+
macroModal.value = { isOpen: true, initialCode: currentKeyCode.value }
227+
}
228+
229+
const closeMacroModal = () => {
230+
macroModal.value.isOpen = false
231+
}
232+
233+
const applyMacroCode = (macroCode: string) => {
234+
currentKeyCode.value = macroCode
235+
closeMacroModal()
236+
}
237+
176238
const coordMapWarning = computed(() => {
177239
// show if any of the selected keys does not have and idx
178240
const keys = keyboardStore.keys.filter((_k, index) => selectedKeys.value.has(index))
@@ -183,4 +245,15 @@ const coordMapWarning = computed(() => {
183245
}
184246
return ''
185247
})
248+
249+
watch(
250+
() => currentKeyCode.value,
251+
(newKeyCode) => {
252+
if (newKeyCode && newKeyCode !== 'No key selected') {
253+
const detectedType = detectKeycodeType(newKeyCode)
254+
keycodeModeForSelection.value = detectedType
255+
}
256+
},
257+
{ immediate: true }
258+
)
186259
</script>

0 commit comments

Comments
 (0)