Ryan Bennett
Ryan Bennett

Reputation: 545

How to create a keyboard shortcut for an input button

I am showing a bunch of pictures and each picture has its own HTML page. I have an input button that onclick will take you to the next link for the picture. However, I want to be able to use my keyboard arrows to go forward and back. I am new to coding and don't know if this is possible. Can I do this with HTML using the accesskey:

<input type="button" accesskey="?" value="Next Item">

Or do I need to use a JQuery plugin? If so, which one?

Upvotes: 42

Views: 89111

Answers (7)

Carson
Carson

Reputation: 7988

for keyboard shortcuts, you can directly handle the keyboard event

document.addEventListener('keyup', (e) => {
    const keys = e.ctrlKey ? ["ctrl"] : []
    if (e.altKey) {
      keys.push("alt")
    }
    document.querySelector(`[data-hotkey~='${keys.join('+')}']`)?.click()
})  

data-hotkey

example

<button data-hotkey="ctrl+z">ctrl+z</button>
<button data-hotkey="ctrl+y">ctrl+y</button>

<script>
  document.addEventListener('keyup', (e) => {
    const keys = e.ctrlKey ? ["ctrl"] : []
    if (e.altKey) {
      keys.push("alt")
    }
    keys.push(e.key)
    document.querySelector(`[data-hotkey~='${keys.join('+')}']`)?.click()
    // console.log(e.key)
  })
  
  // more test
  for (const hotkeyStr of ["u", "U", "alt+c", "alt+ArrowRight", "alt+F1"]) {
    document.body.append(document.createRange().createContextualFragment(
      `<button data-hotkey="${hotkeyStr}">${hotkeyStr}</button>`
    ))
  }

  document.querySelectorAll("button").forEach(elem => elem.onclick = (e) => {
    console.log(e.target.innerText)
  })
</script>


For switching between images using left and right keys, the following approach is provided:

  • Prepare a region for image sets (invisible). <div style="display: none" id="db">
  • When triggering the left or right keys, retrieve the corresponding image from the image set and place the current node in the image set.

<input type="button" data-hotkey="ArrowLeft" value="←">
<input type="button" data-hotkey="ArrowRight" value="→">
<output>
  <svg fill="#00ff00" width="100" height="100" ><g><circle r="10" cx="50" cy="50" ></circle></g></svg>
</output>

<div style="display: none" id="db">
  <svg fill="#0000ff"  width="100" height="100"><g><polygon points="50,20 20,80 80,80"/></g></svg>
  <svg fill="#ff00ff" width="100" height="100"><g><polygon points="50,20 20,80 80,80 90,20" /></g></svg>
</div>

<script>
  document.addEventListener('keyup', (e) => {
    const keys = e.ctrlKey ? ["ctrl"] : []
    if (e.altKey) {
      keys.push("alt")
    }
    keys.push(e.key)
    document.querySelector(`[data-hotkey~='${keys.join('+')}']`)?.click()
  })

  const imgDB = document.querySelector('#db')
  const output = document.querySelector("output")

  const [leftBtn, rightBtn] = document.querySelectorAll("[data-hotkey]")
  leftBtn.onclick = (e) => {
    const cur = document.querySelector("output svg")
    output.append([...imgDB.querySelectorAll("svg")].pop())
    // imgDB.insertAdjacentElement('afterbegin', cur) # use prepend to instead
    imgDB.prepend(cur) // https://developer.mozilla.org/en-US/docs/Web/API/Element/prepend
  }

  rightBtn.onclick = (e) => {
    const cur = document.querySelector("output svg")
    output.append(imgDB.querySelector("svg"))
    imgDB.append(cur)
  }
</script>

When using append, if the node already exists, it will be moved to the target below.

Upvotes: 0

Mariano Desanze
Mariano Desanze

Reputation: 8163

As zzzzBov explained, the HTML accesskey defines a key that will be trapped only when it is combined with the ALT key. That is why that is not useful for trapping any key alone.

But you have to take special care choosing the event to trap the cursor keys because Webkit has decided not to trap them with the keypress event as it is not in the standard. At this moment the other 3 answers here use this keypress event and that is why they don't work in Google Chrome nor Safari, but if you change that to keydown they'll work on all browsers.

You can use this jQuery code to capture the keydown event of the left, right, up, and down arrow keys:

$(window).keydown(function(e) {
  switch (e.keyCode) {
    case 37: // left arrow key
    case 38: // up arrow key
      e.preventDefault(); // avoid browser scrolling due to pressed key
      // TODO: go to previous image
      return;
    case 39: // right arrow key
    case 40: // up arrow key
      e.preventDefault();
      // TODO: go to next image
      return;
  }
});

And in the following code snippet you can see and run a complete example in which images are swapped using the keys or the buttons.

var currentImage = 0;
var imagesArray = [
  'https://upload.wikimedia.org/wikipedia/commons/thumb/3/35/Tux.svg/150px-Tux.svg.png',
  'https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Wikipedia-logo-v2.svg/150px-Wikipedia-logo-v2.svg.png',
  'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e0/Git-logo.svg/150px-Git-logo.svg.png'
];

function hasPrev() {
  return currentImage > 0;
}

function hasNext() {
  return currentImage < imagesArray.length - 1;
}

function goToPrev(e) {
  e.preventDefault();
  if (!hasPrev())
    return;
  currentImage -= 1;
  updateScreen();
}

function goToNext(e) {
  e.preventDefault();
  if (!hasNext())
    return;
  currentImage += 1;
  updateScreen();
}

function updateScreen() {
  $('#imgMain').attr('src', imagesArray[currentImage]);
  $('#btnPrev').prop('disabled', !hasPrev());
  $('#btnNext').prop('disabled', !hasNext());
}

$(document).ready(function() {
  updateScreen();
  $('#btnPrev').click(goToPrev);
  $('#btnNext').click(goToNext);
});

var keyCodes = {
  left: 37,
  up: 38,
  right: 39,
  down: 40
};

$(window).keydown(function(e) {
  switch (e.keyCode) {
    case keyCodes.left:
    case keyCodes.up:
      goToPrev(e);
      return;
    case keyCodes.right:
    case keyCodes.down:
      goToNext(e);
      return;
  }
});
button:enabled kbd {
  color: green;
  font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btnPrev">
  Previous Image
  <br/>
  <small>(arrow keys: <kbd>left</kbd> or <kbd>up</kbd>)</small>
</button>
<button id="btnNext">
  Next Image
  <br/>
  <small>(arrow keys: <kbd>right</kbd> or <kbd>down</kbd>)</small>
</button>
<br/>
<img id="imgMain" src="">

UPDATE (May 2016)

keyCode has recently been deprecated (but I haven't found a cross-browser solution yet). Quoting MDN article for keyCode:

Deprecated

This feature has been removed from the Web standards. Though some browsers may still support it, it is in the process of being dropped. Do not use it in old or new projects. Pages or Web apps using it may break at any time.

...

This shouldn't be used by new web applications. IE and Firefox already (partially) support KeyboardEvent.key. Also, Google Chrome and Safari support KeyboardEvent.keyIdentifier which is defined in the old draft of DOM Level 3 Events. If you can use them or one of them, you should use them/it as far as possible.

Upvotes: 36

PutihTua
PutihTua

Reputation: 112

I will use this :

<input type="button" accesskey="n" value="Next Item">

And the user should type : shift + alt + n

Upvotes: 2

babygreat
babygreat

Reputation: 361

I just used a third party shortcut.js. It's very friendly. You can reference it.

<script type="text/javascript" src="js/shortcut.js"></script>

<script>
    shortcut.add("alt+s", function() {
        // Do something
    });   
    shortcut.add("ctrl+enter", function() {
        // Do something
    }); 
</script>

Upvotes: 32

zzzzBov
zzzzBov

Reputation: 179046

Can I do this with HTML using the accesskey:

No, accesskey is used in conjunction with alt

So accesskey="a" will make Alt+A be the shortcut.

Or do I need to use a jQuery plugin?

No, you can use regular old javascript; jQuery works too.

$(window).keypress(function(e){
  var code = e.which || e.keyCode;
  switch ( code )
  {
    case 43:
      //do stuff
      return false;
    default:
      break;
  }
});

Upvotes: 9

Milan Jaric
Milan Jaric

Reputation: 5646

I did example in jsFiddle it uses arrow key up and down so it focuses next or previous input control respectively . Take a look

Upvotes: 2

alex
alex

Reputation: 490243

You could do this...

$(window).keypress(function(event) {
    switch (event.keyCode) {

    case 37:
        prev();
        break;
    case 39:
        next();
        break;

    }
});

jsFiddle.

Upvotes: 1

Related Questions