首页 > 解决方案 > 一些关键事件阻止其他事件触发

问题描述

首先,这是我正在研究的实时应用程序:turbo_synth

我正在使用 VueJS 制作它,但是,我相信这个问题与 Vue 无关。

问题: 除了尝试弹奏某些音符组合(例如,尝试弹奏 Q、W 和 2 键)之外,一切都很好,而且很花哨。你会注意到最后一个音符没有被弹奏,甚至没有显示为按下,而您可以同时播放 Q、W、E、R 和 Y。所以它似乎没有限制,就像我之前想的那样?

代码:我正在使用 vue-keypress 来轻松处理全局的关键事件。

模板部分

<template>
    <div id="app">
        <h1>Basic oscillator test</h1>
        <label for="waveType">Choose a wave type:</label>

        <select
            name="waveType"
            id="waveType"
            v-model="wave"
        >
            <option value="sine">sine</option>
            <option value="square">square</option>
            <option value="triangle">triangle</option>
            <option value="sawtooth">sawtooth</option>
        </select>

        <hr>

        <ul class="keyboard">
            <li
                v-for="note in testBoard"
                :key="note.id"
                :class="[note.class, getKeyByValue(testBoard, note).charAt(0), {'pressed': pressedNotes.includes(note.freq)}]"
                @mousedown="playSound(note.freq, 1)"
            >
                <p>{{getKeyByValue(testBoard, note).replace('s', '#')}}</p>
                <p>{{String.fromCharCode(note.keycode)}}</p>
            </li>
        </ul>

        <Keypress
            v-for="note in testBoard"
            :key="note.id"
            key-event="keydown"
            :key-code="note.keycode"
            @success="playSound(note.freq)"
        />
        <Keypress
            v-for="note in testBoard"
            :key="note.id"
            key-event="keyup"
            :key-code="note.keycode"
            @success="removeNote(note.freq)"
        />
    </div>
</template>

脚本部分:

<script>
import { noteValues, testBoard } from './assets/notevalues.js';
export default {
    name: 'App',
    data() {
        return {
            noteValues,
            testBoard,
            selectedNote: null,
            wave: 'sine',
            pressedNotes: [],
        }
    },
    components: {
        Keypress: () => import('vue-keypress')
    },
    methods: {
        getKeyByValue(object, value) {
            return Object.keys(object).find(key => object[key] === value);
        }
        ,
        playSound(note, clicked) {
            if (this.pressedNotes.includes(note)) {
                return;
            } else {
                this.pressedNotes.push(note);
                const context = new AudioContext();
                const o = context.createOscillator();
                const g = context.createGain();
                o.connect(g);
                g.connect(context.destination);
                o.type = this.wave;
                const frequency = note;
                o.frequency.value = frequency;
                o.start(0);
                o.stop(context.currentTime + 1)
                g.gain.exponentialRampToValueAtTime(
                    0.00001, context.currentTime + 2.5
                );
                setTimeout(() => {
                    context.close();
                }, 1000);
                if (clicked === 1) {
                    setTimeout(() => {
                        this.removeNote(note);
                    }, 50)
                }
            }
        },
        removeNote(note) {
            const index = this.pressedNotes.indexOf(note);
            if (index > -1) {
                this.pressedNotes.splice(index, 1);
            }
        }
    },
}
</script>

这是笔记列表:

export let testBoard = {
  'C3': { keycode: 81, freq: 130.81, class: 'white' },
  'Cs3': { keycode: 50, freq: 138.59, class: 'black' },
  'D3': { keycode: 87, freq: 146.83, class: 'white' },
  'Ds3': { keycode: 51, freq: 155.56, class: 'black' },
  'E3': { keycode: 69, freq: 164.81, class: 'white' },
  'F3': { keycode: 82, freq: 174.61, class: 'white' },
  'Fs3': { keycode: 53, freq: 185.00, class: 'black' },
  'G3': { keycode: 84, freq: 196.00, class: 'white' },
  'Gs3': { keycode: 54, freq: 207.65, class: 'black' },
  'A3': { keycode: 89, freq: 220.00, class: 'white' },
  'As3': { keycode: 55, freq: 233.08, class: 'black' },
  'B3': { keycode: 85, freq: 246.94, class: 'white' },
  'C4': { keycode: 90, freq: 261.63, class: 'white' },
  'Cs4': { keycode: 83, freq: 277.18, class: 'black' },
  'D4': { keycode: 88, freq: 293.66, class: 'white' },
  'Ds4': { keycode: 68, freq: 311.13, class: 'black' },
  'E4': { keycode: 67, freq: 329.63, class: 'white' },
  'F4': { keycode: 86, freq: 349.23, class: 'white' },
  'Fs4': { keycode: 71, freq: 369.99, class: 'black' },
  'G4': { keycode: 66, freq: 392.00, class: 'white' },
  'Gs4': { keycode: 72, freq: 415.30, class: 'black' },
  'A4': { keycode: 78, freq: 440.00, class: 'white' },
  'As4': { keycode: 74, freq: 466.16, class: 'black' },
  'B4': { keycode: 77, freq: 493.88, class: 'white' }
}

我也尝试过其他人用 vue 或其他技术制作的钢琴,总是有类似的问题。我可能遗漏了一些重要的东西,谁知道呢,但我找不到我需要的信息。

谢谢一堆

标签: javascriptvue.jskeyeventpiano

解决方案


您的代码没有任何问题,您也无法修复它——这是许多键盘的硬件限制。

首先,想象一下键盘布局为一个矩形网格(换句话说,1QAZ位于同一列中,即使它们通常不在彼此正上方)。

限制是不能同时识别形成矩形三个角的三个键。如果您连续按住两个键,则第三个键不能与前两个键中的任何一个位于同一列。如果您在一列中按住两个键,则第三个键不能与前两个键中的任何一个在同一行。如果按住Qand Z,那么以 开头的行上的任何键A都可以正常工作,但是W, E, X,C等都将被锁定。

或者,某些机器可能会在矩形的第四个角为您提供“幽灵”按键 - 按住QZ按下E将注册一个按键E,但同时也会注册一个按键C,即使没有人按下C

所有这一切都与电子键盘的制造方式有关,而您在软件中无能为力。有些键盘没有此限制,但您不能指望您的用户拥有它们。


推荐阅读