All checks were successful
Build and copy to prod / build-and-copy (push) Successful in 2m10s
71 lines
2.3 KiB
Markdown
71 lines
2.3 KiB
Markdown
---
|
|
title: "Cursed components: a dvorak-only text input"
|
|
date: 2024-04-19T11:00:00.000Z
|
|
tags:
|
|
- javascript
|
|
- html
|
|
- draft
|
|
---
|
|
|
|
This post was inspired by Terence Eden's post about [inputs that don't work with numpads](https://shkspr.mobi/blog/2024/04/i-cant-use-my-number-pad-for-2fa-codes/), and one of the [subsequent comments](https://mastodon.social/@Edent/112286509959315116). This got me thinking, wouldn't it be absolutely beyond cursed to have a text input that only allowed you to enter text if you were using a sufficiently cool keyboard layout.
|
|
|
|
So, I present, the Dvorak-only Text Input:
|
|
|
|
**TODO:** Make the input
|
|
<dvorak-only>
|
|
<textarea slot="input"></textarea>
|
|
</dvorak-only>
|
|
|
|
## Detecting keyboard layout
|
|
|
|
There's no _actual_ way to detect the keyboard layout as a named value using Javascript, but there is the [KeyboardLayoutMap](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardLayoutMap), which is currently supported in Chromium browsers and not much else[^1]. So what we can do is lookup how the user's keyboard layout maps particular keys, and then compare those to what we'd expect from a Dvorak layout.
|
|
|
|
|
|
```javascript
|
|
const dvorakKeys = [
|
|
["KeyQ", "'"],
|
|
["KeyW", ","],
|
|
["KeyE", "."],
|
|
["KeyR", "p"],
|
|
["KeyT", "y"],
|
|
["KeyY", "f"]
|
|
];
|
|
navigator.keyboard.getLayoutMap().then(layoutMap => {
|
|
const isUsingDvorak = dvorakKeys.every(
|
|
([keyCode, expected]) => layoutMap.get(keyCode) === expected
|
|
);
|
|
if (isUsingDvorak) {
|
|
// The user is (probably) using Dvorak
|
|
}
|
|
})
|
|
```
|
|
|
|
Because this call happens inside a Promise, it can't be directly used within an `onChange` event on the text input, so instead it rechecks every 200ms and stores the result:
|
|
|
|
```javascript
|
|
let isDvorak = false;
|
|
const dvorakKeys = [
|
|
["KeyQ", "'"],
|
|
["KeyW", ","],
|
|
["KeyE", "."],
|
|
["KeyR", "p"],
|
|
["KeyT", "y"],
|
|
["KeyY", "f"]
|
|
];
|
|
setInterval(
|
|
() => navigator.keyboard.getLayoutMap().then(layoutMap => {
|
|
isDvorak = dvorakKeys.every(
|
|
([keyCode, expected]) => layoutMap.get(keyCode) === expected
|
|
);
|
|
}),
|
|
200
|
|
);
|
|
```
|
|
|
|
## Preventing the input
|
|
|
|
This part's pretty simple. Basically, just
|
|
|
|
[^1]: But that's pretty on-brand for this particular use-case.
|
|
|
|
<script src="/assets/js/dvorak-only.js" defer></script> |