【JS】Ctrl(Command)キー押しながらクリックされたかどうか判定する


## Ctrl(Command)キークリックかどうか判定したい

clickイベント時に生成される `MouseEvent` の `ctrlKey` と `metaKey` を使って判定します。

例として、通常クリック時はインクリメント、Ctrl(Command) + クリック時はデクリメントするカウンターを実装してみます。
ReactとVanilaJSの2パターン実装してみました。

## React

```tsx:React(17.0.2)
const Button: React.FC = () => {
  const [count, setCount] = React.useState(0)
  
  const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
    if ((e.ctrlKey && !e.metaKey) || (!e.ctrlKey && e.metaKey)) {
      setCount(count - 1)
    } else {
      setCount(count + 1)
    }
  }
  
  return (
    <>
      <button onClick={handleClick}>
        クリックでインクリメント、Ctrl+クリックでデクリメント
      </button>

      <div>
        <span>カウント: </span><span>{count}</span>
      </div>
    </>
  )
}
```

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="js,result" data-user="mishiwata1015" data-slug-hash="MWpJREd" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Ctrl+クリックでデクリメント（React）">
  <span>See the Pen <a href="https://codepen.io/mishiwata1015/pen/MWpJREd">
  Ctrl+クリックでデクリメント（React）</a> by mishiwata1015 (<a href="https://codepen.io/mishiwata1015">@mishiwata1015</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## 素朴なHTML + JS

```html:HTML
<button id="button">
  クリックでインクリメント、Ctrl+クリックでデクリメント
</button>

<div>
  <span>カウント: </span><span id="count">0</span>
</div>
```

```js:JS
let count = 0

document.getElementById('button').onclick = function handleClick(e) {
  if ((e.ctrlKey && !e.metaKey) || (!e.ctrlKey && e.metaKey)) {
    count--
  } else {
    count++
  }
  
  document.getElementById('count').textContent = count
}
```

<p class="codepen" data-height="265" data-theme-id="light" data-default-tab="js,result" data-user="mishiwata1015" data-slug-hash="rNyjvXe" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Ctrl+クリックでデクリメント（VanilaJS）">
  <span>See the Pen <a href="https://codepen.io/mishiwata1015/pen/rNyjvXe">
  Ctrl+クリックでデクリメント（VanilaJS）</a> by mishiwata1015 (<a href="https://codepen.io/mishiwata1015">@mishiwata1015</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## MouseEvent.ctrlKey


Ctrlキーが押されてたどうか取得できます。

https://developer.mozilla.org/ja/docs/Web/API/MouseEvent/ctrlKey

> 読み取り専用プロパティ MouseEvent.ctrlKey は、イベント発生時に control キーが押されたかどうかを、押されていた (true) または押されていない (false) のBoolean で返します。

そのまんまですね。

## MouseEvent.metaKey

メタキーが押されていたかどうか取得できます。
どのキーがメタキーに該当するかは環境に依存します。

https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/metaKey

> On Macintosh keyboards, this key is the command key (⌘). On Windows keyboards, this key is the Windows key (⊞).

つまり、Windowsの場合はWindowsキー(⊞)、Macの場合はCommandキー(⌘)が押されていたかどうか取得できます。

## まとめ

MouseEvent`.ctrlKey` と `MouseEvent.metaKey` を使って以下のように判定することで、Ctrl(Command)キー押しながらクリックされたかどうか判定できます。

- Windows用: `ctrlKey: true && metaKey: false`
- Mac用: `ctrlKey: false && metaKey: true`

ちなみに、↑のコードはMacで動くことは確認しましたが、Windowsでは動作確認できてないです。
どなたか動くかどうか教えてもらえると助かります :bow:

## 参考

https://developer.mozilla.org/ja/docs/Web/API/Element/click_event

https://developer.mozilla.org/ja/docs/Web/API/MouseEvent