Выполнение комбинаций клавиш с помощью jQuery/JavaScript

Мне любопытно, как я, со следующим кодом плагина jQuery, который я пишу внизу этого вопроса, мог реализовать комбинации клавиш. Как это работает до сих пор, это позволяет пользователю создавать ключевые команды, просто выполняя обычный синтаксис, подобный jQuery, и предоставлять событие для ключевой команды, например так:

$(window).jkey('a',function(){
   alert('you pressed the a key!');
});

or

$(window).jkey('b c d',function(){
   alert('you pressed either the b, c, or d key!');
});

и, наконец, то, что я хочу, это способность делать, но не могу понять:

$(window).jkey('alt+n',function(){
   alert('you pressed alt+n!');
});

Я знаю, как это сделать вне плагина (при нажатии клавиши установите переменную false, а при нажатии клавиши установите переменную true и проверьте, истинна ли переменная, когда вы нажимаете другую клавишу), но я не знаю, как это сделать, когда вы не знаете, какие клавиши будут нажаты и сколько. Как добавить эту поддержку? Я хочу иметь возможность разрешить им делать что-то вроде alt+shift+a или a+s+d+f, если они захотят. Я просто не могу понять, как это реализовать. Любые идеи?

Я собираюсь выпустить это как плагин с открытым исходным кодом, и я хотел бы дать тому, кто дает мне право, работает, ответить на некоторые кредиты в сообщении в блоге и в коде, который он сам. Заранее спасибо!

(function($) {
  $.fn.jkey = function(keyCombo,callback) {
    if(keyCombo.indexOf(' ') > -1){ //If multiple keys are selected
        var keySplit = keyCombo.split(' ');
    }
    else{ //Else just store this single key
        var keySplit = [keyCombo];
    }
    for(x in keySplit){ //For each key in the array...

        if(keySplit[x].indexOf('+') > -1){
            //Key selection by user is a key combo... what now?
        }
        else{
            //Otherwise, it's just a normal, single key command
        }

        switch(keySplit[x]){
            case 'a':
                keySplit[x] = 65;
                break;
            case 'b':
                keySplit[x] = 66;
                break;
            case 'c':
                keySplit[x] = 67;
                break;
            //And so on for all the rest of the keys
        }
    }
    return this.each(function() {
        $this = $(this);
        $this.keydown(function(e){
            if($.inArray(e.keyCode, keySplit) > -1){ //If the key the user pressed is matched with any key the developer set a key code with...
                if(typeof callback == 'function'){ //and they provided a callback function
                    callback(); //trigger call back and...
                    e.preventDefault(); //cancel the normal
                }
            }
        });
    });
  }
})(jQuery);

person Oscar Godson    schedule 02.11.2010    source источник


Ответы (4)


Вот что я придумал. По сути, я создал объект JSON, в котором хранятся все коды клавиш. Затем я заменяю все предоставленные ключи кодами. Если клавиши используют «+» для создания комбинации клавиш, я затем создаю из нее массив кодов.

Затем мы создаем еще один массив, в котором хранятся все нажатые клавиши (keyDown добавляет элемент, keyUp удаляет его). На keyDown мы проверяем, является ли это одной клавишей или комбинацией. Если это комбинация, мы проверяем ее по всем текущим активным нажатиям клавиш. Если они все совпадают, мы выполняем обратный вызов.

Это будет работать с любым количеством комбинаций клавиш. Единственный раз, когда я видел, что он не работает, это когда вы используете «оповещение ()» для отображения сообщения о комбинации клавиш, потому что он больше не будет удалять элементы из активного массива нажатия клавиш.

(function($) { 
  $.fn.jkey = function(keyCombo,callback) {

    // Save the key codes to JSON object
    var keyCodes = { 
      'a'   : 65,
      'b'   : 66,
      'c'   : 67,
      'alt' : 18
    };

    var x = '';
    var y = '';

    if(keyCombo.indexOf(' ') > -1){ //If multiple keys are selected
        var keySplit = keyCombo.split(' ');
    }
    else{ //Else just store this single key
        var keySplit = [keyCombo];
    }

    for(x in keySplit){ //For each key in the array...

      if(keySplit[x].indexOf('+') > -1){
        //Key selection by user is a key combo
        // Create a combo array and split the key combo
        var combo = Array();
        var comboSplit = keySplit[x].split('+');

        // Save the key codes for each element in the key combo
        for(y in comboSplit){
          combo[y] = keyCodes[ comboSplit[y] ];
        }

        keySplit[x] = combo;

      } else {
        //Otherwise, it's just a normal, single key command
        keySplit[x] = keyCodes[ keySplit[x] ];
      }

    }

    return this.each(function() {
        $this = $(this);

        // Create active keys array
        // This array will store all the keys that are currently being pressed
        var activeKeys = Array();

        $this.keydown(function(e){

          // Save the current key press
          activeKeys[ e.keyCode ] = e.keyCode;

          if($.inArray(e.keyCode, keySplit) > -1){ // If the key the user pressed is matched with any key the developer set a key code with...

            if(typeof callback == 'function'){ //and they provided a callback function
              callback(); //trigger call back and...
              e.preventDefault(); //cancel the normal
            }

          } else { // Else, the key did  not match which means it's either a key combo or just dosn't exist

            // Check if the individual items in the key combo match what was pressed
            for(x in keySplit){
              if($.inArray(e.keyCode, keySplit[x]) > -1){

                // Initiate the active variable
                var active = 'unchecked';

                // All the individual keys in the combo with the keys that are currently being pressed
                for(y in keySplit[x]) {
                  if(active != false) {
                    if($.inArray(keySplit[x][y], activeKeys) > -1){
                      active = true;
                    } else {
                      active = false;
                    }
                  }
                }

                // If all the keys in the combo are being pressed, active will equal true
                if(active === true){
                  if(typeof callback == 'function'){ //and they provided a callback function
                    callback(); //trigger call back and...
                    e.preventDefault(); //cancel the normal
                  }
                }
              }
            }

          } // end of if in array

        }).keyup(function(e) {
          // Remove the current key press
          activeKeys[ e.keyCode ] = '';
        });

    });

  }
})(jQuery);
person sebnitu    schedule 04.11.2010
comment
Вы определяете x в глобальной области. - person Josh Stodola; 05.11.2010
comment
Я думаю, что проблему с областью действия можно решить, определив x и y следующим образом: var x = ''; вар у = ''; ? - person sebnitu; 05.11.2010
comment
Или, что еще лучше, мы можем определить их, добавив var в оператор for? for(var x в keySplit){... - person sebnitu; 05.11.2010

Используйте нажатие клавиши вместо keyup/keydown, потому что последние два неточно передают код клавиши (ссылка, см. последний абзац). В этом случае вы можете ссылаться на логические свойства altKey ctrlKey и shiftKey объекта события...

$(document).keypress(function(e) {
  var key = String.fromCharCode(e.which);
  var alt = e.altKey;
  var ctrl = e.ctrlKey
  var shift = e.shiftKey;
  alert("Key:" + key + "\nAlt:" + alt + "\nCtrl:" + ctrl + "\nShift:" + shift);
});

Кроме того, вы можете использовать String.fromCharCode для преобразования кода клавиши в реальную букву.

Вы не можете захватить несколько клавиш, кроме комбинаций с Ctrl, Alt и Shift. Вы просто не можете сделать это в одном мероприятии. Так что выбросьте идею a+s+d+f в окно.

Примечание. Очевидно, что браузер использует определенные комбинации клавиш. Например, Alt + F обычно вызывает меню «Файл» в Windows. Ctrl + N обычно запускает новое окно/вкладку. не пытайтесь переопределить любую из этих комбинаций.

Вот демонстрация для вашего удовольствия.

person Josh Stodola    schedule 04.11.2010
comment
Итак, как мне это интегрировать и как мне интегрировать его, чтобы работала любая комбинация клавиш, например. shift+alt+f+d+s, если они хотят. Как я уже сказал, это для меня, но оно также будет опубликовано публично, поэтому мне все еще нужно разрешить затем переопределять настройки браузера по умолчанию, такие как ctrl + t, хотя я бы никогда этого не сделал :) - person Oscar Godson; 04.11.2010
comment
Упс, тогда как насчет shift+alt+f, как мне интегрировать это в плагин, извините - person Oscar Godson; 04.11.2010
comment
Вы не можете перехватить несколько ключей, так что забудьте об этом. Событие запускается один раз при нажатии клавиши. Логические индикаторы просто сообщают вам, были ли нажаты клавиши Ctrl, Alt или Shift при нажатии клавиши. Что касается переопределения настроек браузера по умолчанию, нет, НЕТ и НЕТ! - person Josh Stodola; 04.11.2010
comment
@Oscar В ответ на ваш второй комментарий: if(key == "F" && alt && shift) { alert("OK!"); } - person Josh Stodola; 04.11.2010
comment
@Oscar А shift+alt+f может даже не работать, потому что в браузере, вероятно, уже что-то подключено для alt+f. - person Josh Stodola; 04.11.2010
comment
И, как я уже сказал, IM не собирается переопределять их, однако было бы глупо предполагать, как другие будут использовать плагин. Не говоря уже о том, что в других странах разные ключи будут соответствовать разным событиям браузера... Опять же, IM не собирается переопределять их, это будет раздражать. - person Oscar Godson; 04.11.2010
comment
shift+alt+f, кажется, тоже работает нормально... просто alt+f конфликтует (я не использую это, хотя...) Лично я хочу использовать alt+s, alt+n, alt+l, ctrl+ alt+стрелка влево и ctrl+alt+стрелка вправо, - person Oscar Godson; 04.11.2010

Это просто выстрел в темноту, но, возможно, он поможет вам встать на правильный путь.

Если возможно, чтобы эта функция распознавала шестнадцатеричное значение для введенного вами ключа вместо буквального ключа (например, 0x6E для буквы «n»), вы могли бы получить, что «alt+n» переводится в шестнадцатеричном виде, и иметь функция ищет это значение.

person Infotekka    schedule 04.11.2010
comment
Ой, интересно, плохо посмотрю. Спасибо! Кроме того, у вас есть ссылка на то, как их конвертировать через JS? Я еще не гуглил... - person Oscar Godson; 04.11.2010

Если вы ищете что-то, что позволит пользователю легко вводить и определять комбинации клавиш с помощью простого поля ввода, я написал плагин, который сделает это за вас: http://suan.github.com/jquery-keycombinator/

person Suan    schedule 01.05.2012