Skip to content

Instantly share code, notes, and snippets.

@PyYoshi
Last active June 20, 2025 10:20
Show Gist options
  • Select an option

  • Save PyYoshi/e9c31855d4c1db8c89108c05ba28a2f7 to your computer and use it in GitHub Desktop.

Select an option

Save PyYoshi/e9c31855d4c1db8c89108c05ba28a2f7 to your computer and use it in GitHub Desktop.
Macropad EEPROM キーコード変換ツール https://github.com/MrGeorgeK55/Macropad-3-keys-1-knob
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Macropad EEPROM キーコード変換ツール</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
}
h1 {
color: #333;
text-align: center;
}
.container {
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
margin-bottom: 20px;
}
.key-config {
border: 1px solid #ddd;
padding: 15px;
margin: 10px 0;
border-radius: 5px;
background: #fafafa;
}
.key-config h3 {
margin-top: 0;
color: #555;
}
label {
display: inline-block;
width: 120px;
font-weight: bold;
color: #666;
}
select, input[type="number"], input[type="text"] {
margin: 5px;
padding: 5px;
border: 1px solid #ccc;
border-radius: 3px;
}
select {
width: 200px;
}
input[type="number"] {
width: 60px;
}
.macro-keys {
margin-top: 10px;
padding: 10px;
background: #f0f0f0;
border-radius: 3px;
}
.output {
font-family: monospace;
background: #222;
color: #0f0;
padding: 15px;
border-radius: 5px;
white-space: pre;
overflow-x: auto;
}
button {
background: #4CAF50;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
margin: 10px 5px;
}
button:hover {
background: #45a049;
}
.info {
background: #e3f2fd;
padding: 10px;
border-radius: 5px;
margin: 10px 0;
font-size: 14px;
}
.modifier-info {
font-size: 12px;
color: #666;
margin-top: 5px;
}
</style>
</head>
<body>
<div style="text-align: center; margin-bottom: 20px;">
<button onclick="toggleLanguage()" style="background: #2196F3; font-size: 14px; padding: 5px 15px;">🌐 English/日本語</button>
</div>
<h1 id="main-title">Macropad EEPROM キーコード変換ツール</h1>
<div class="container">
<h2 id="config-title">キー設定</h2>
<div class="info" id="config-info">
各キー(3個のキー + エンコーダースイッチ + エンコーダー回転CW/CCW)の動作を設定します。
トグル機能を使用すると、1つのキーで2つの異なる動作を切り替えることができます。
</div>
<!-- Key 1 -->
<div class="key-config" id="key1-container">
<h3>キー 1</h3>
<label>キータイプ:</label>
<select id="key1-type" onchange="updateKeyType(1)">
<option value="0">キーボードキー</option>
<option value="1">コンシューマーキー</option>
<option value="2">マクロキー</option>
</select>
<div id="key1-config"></div>
</div>
<!-- Key 2 -->
<div class="key-config" id="key2-container">
<h3>キー 2</h3>
<label>キータイプ:</label>
<select id="key2-type" onchange="updateKeyType(2)">
<option value="0">キーボードキー</option>
<option value="1">コンシューマーキー</option>
<option value="2">マクロキー</option>
</select>
<div id="key2-config"></div>
</div>
<!-- Key 3 -->
<div class="key-config" id="key3-container">
<h3>キー 3</h3>
<label>キータイプ:</label>
<select id="key3-type" onchange="updateKeyType(3)">
<option value="0">キーボードキー</option>
<option value="1">コンシューマーキー</option>
<option value="2">マクロキー</option>
</select>
<div id="key3-config"></div>
</div>
<!-- Encoder Switch -->
<div class="key-config" id="key4-container">
<h3>エンコーダースイッチ</h3>
<label>キータイプ:</label>
<select id="key4-type" onchange="updateKeyType(4)">
<option value="0">キーボードキー</option>
<option value="1">コンシューマーキー</option>
<option value="2">マクロキー</option>
</select>
<div id="key4-config"></div>
</div>
<!-- Encoder CW -->
<div class="key-config" id="key5-container">
<h3>エンコーダー時計回り</h3>
<label>キータイプ:</label>
<select id="key5-type" onchange="updateKeyType(5)">
<option value="0">キーボードキー</option>
<option value="1">コンシューマーキー</option>
<option value="2">マクロキー</option>
</select>
<div id="key5-config"></div>
</div>
<!-- Encoder CCW -->
<div class="key-config" id="key6-container">
<h3>エンコーダー反時計回り</h3>
<label>キータイプ:</label>
<select id="key6-type" onchange="updateKeyType(6)">
<option value="0">キーボードキー</option>
<option value="1">コンシューマーキー</option>
<option value="2">マクロキー</option>
</select>
<div id="key6-config"></div>
</div>
<button onclick="generateEEPROM()">EEPROM データ生成</button>
<button onclick="copyToClipboard()">クリップボードにコピー</button>
<button onclick="downloadBinary()">バイナリファイルをダウンロード</button>
<div style="margin-top: 15px;">
<label for="fileInput" style="background: #2196F3; color: white; padding: 10px 20px; border-radius: 5px; cursor: pointer;">
バイナリファイルを読み込む
</label>
<input type="file" id="fileInput" accept=".bin,.eeprom" style="display: none;" onchange="loadBinary(event)">
</div>
</div>
<div class="container">
<h2 id="output-title">EEPROM データ出力</h2>
<div id="output" class="output">ここに生成されたEEPROMデータが表示されます</div>
</div>
<script>
// Language support
let currentLang = 'ja';
const translations = {
ja: {
title: "Macropad EEPROM キーコード変換ツール",
configTitle: "キー設定",
configInfo: "各キー(3個のキー + エンコーダースイッチ + エンコーダー回転CW/CCW)の動作を設定します。\nトグル機能を使用すると、1つのキーで2つの異なる動作を切り替えることができます。",
outputTitle: "EEPROM データ出力",
outputDefault: "ここに生成されたEEPROMデータが表示されます",
key1: "キー 1",
key2: "キー 2",
key3: "キー 3",
encoderSwitch: "エンコーダースイッチ",
encoderCW: "エンコーダー時計回り",
encoderCCW: "エンコーダー反時計回り",
keyType: "キータイプ:",
keyboardKey: "キーボードキー",
consumerKey: "コンシューマーキー",
macroKey: "マクロキー",
toggleState1: "トグル状態1",
toggleState2: "トグル状態2",
modifier: "修飾キー:",
keycode: "キーコード:",
function: "機能:",
macroCount: "マクロキー数:",
key: "キー",
toggleInfo: "トグル機能: キーを押すたびに状態1と状態2が切り替わります",
generateBtn: "EEPROM データ生成",
copyBtn: "クリップボードにコピー",
downloadBtn: "バイナリファイルをダウンロード",
loadBtn: "バイナリファイルを読み込む",
alertCopy: "クリップボードにコピーしました!",
alertGenerate: "先にEEPROMデータを生成してください",
alertSize: "ファイルサイズが小さすぎます。最低72バイト必要です。",
alertLoaded: "バイナリファイルを読み込みました",
none: "なし",
unknown: "不明"
},
en: {
title: "Macropad EEPROM Keycode Converter",
configTitle: "Key Configuration",
configInfo: "Configure the behavior of each key (3 keys + encoder switch + encoder rotation CW/CCW).\nToggle function allows you to switch between two different actions with one key.",
outputTitle: "EEPROM Data Output",
outputDefault: "Generated EEPROM data will be displayed here",
key1: "Key 1",
key2: "Key 2",
key3: "Key 3",
encoderSwitch: "Encoder Switch",
encoderCW: "Encoder Clockwise",
encoderCCW: "Encoder Counter-Clockwise",
keyType: "Key Type:",
keyboardKey: "Keyboard Key",
consumerKey: "Consumer Key",
macroKey: "Macro Key",
toggleState1: "Toggle State 1",
toggleState2: "Toggle State 2",
modifier: "Modifier:",
keycode: "Keycode:",
function: "Function:",
macroCount: "Macro Key Count:",
key: "Key",
toggleInfo: "Toggle function: Switches between state 1 and state 2 each time the key is pressed",
generateBtn: "Generate EEPROM Data",
copyBtn: "Copy to Clipboard",
downloadBtn: "Download Binary File",
loadBtn: "Load Binary File",
alertCopy: "Copied to clipboard!",
alertGenerate: "Please generate EEPROM data first",
alertSize: "File size too small. Minimum 72 bytes required.",
alertLoaded: "Binary file loaded",
none: "None",
unknown: "Unknown"
}
};
function t(key) {
return translations[currentLang][key] || key;
}
function toggleLanguage() {
currentLang = currentLang === 'ja' ? 'en' : 'ja';
updateUILanguage();
}
function updateUILanguage() {
document.getElementById('main-title').textContent = t('title');
document.getElementById('config-title').textContent = t('configTitle');
document.getElementById('config-info').textContent = t('configInfo');
document.getElementById('output-title').textContent = t('outputTitle');
// Update key labels
const keyNames = [t('key1'), t('key2'), t('key3'), t('encoderSwitch'), t('encoderCW'), t('encoderCCW')];
for (let i = 1; i <= 6; i++) {
const container = document.getElementById(`key${i}-container`);
if (container) {
const h3 = container.querySelector('h3');
if (h3) h3.textContent = keyNames[i-1];
const label = container.querySelector('label');
if (label) label.textContent = t('keyType');
const select = document.getElementById(`key${i}-type`);
if (select) {
select.options[0].textContent = t('keyboardKey');
select.options[1].textContent = t('consumerKey');
select.options[2].textContent = t('macroKey');
}
}
// Update the key type configuration if it's already displayed
updateKeyType(i);
}
// Update buttons
const buttons = document.querySelectorAll('button');
buttons[1].textContent = t('generateBtn');
buttons[2].textContent = t('copyBtn');
buttons[3].textContent = t('downloadBtn');
// Update file input label
document.querySelector('label[for="fileInput"]').textContent = t('loadBtn');
// Update output if it's default text
const outputText = document.getElementById('output').textContent;
if (outputText === translations['ja'].outputDefault || outputText === translations['en'].outputDefault) {
document.getElementById('output').textContent = t('outputDefault');
}
}
// USB HID キーコード定義
const keyboardCodes = {
"なし": 0x00,
"A": 0x04, "B": 0x05, "C": 0x06, "D": 0x07, "E": 0x08, "F": 0x09,
"G": 0x0A, "H": 0x0B, "I": 0x0C, "J": 0x0D, "K": 0x0E, "L": 0x0F,
"M": 0x10, "N": 0x11, "O": 0x12, "P": 0x13, "Q": 0x14, "R": 0x15,
"S": 0x16, "T": 0x17, "U": 0x18, "V": 0x19, "W": 0x1A, "X": 0x1B,
"Y": 0x1C, "Z": 0x1D,
"1": 0x1E, "2": 0x1F, "3": 0x20, "4": 0x21, "5": 0x22,
"6": 0x23, "7": 0x24, "8": 0x25, "9": 0x26, "0": 0x27,
"Enter": 0x28, "Escape": 0x29, "Backspace": 0x2A, "Tab": 0x2B,
"Space": 0x2C, "-": 0x2D, "=": 0x2E, "[": 0x2F, "]": 0x30,
"\\": 0x31, ";": 0x33, "'": 0x34, "`": 0x35, ",": 0x36,
".": 0x37, "/": 0x38,
"F1": 0x3A, "F2": 0x3B, "F3": 0x3C, "F4": 0x3D, "F5": 0x3E,
"F6": 0x3F, "F7": 0x40, "F8": 0x41, "F9": 0x42, "F10": 0x43,
"F11": 0x44, "F12": 0x45,
"PrintScreen": 0x46, "ScrollLock": 0x47, "Pause": 0x48,
"Insert": 0x49, "Home": 0x4A, "PageUp": 0x4B,
"Delete": 0x4C, "End": 0x4D, "PageDown": 0x4E,
"Right": 0x4F, "Left": 0x50, "Down": 0x51, "Up": 0x52,
"NumLock": 0x53,
"KP /": 0x54, "KP *": 0x55, "KP -": 0x56, "KP +": 0x57,
"KP Enter": 0x58, "KP 1": 0x59, "KP 2": 0x5A, "KP 3": 0x5B,
"KP 4": 0x5C, "KP 5": 0x5D, "KP 6": 0x5E, "KP 7": 0x5F,
"KP 8": 0x60, "KP 9": 0x61, "KP 0": 0x62, "KP .": 0x63
};
const modifierCodesJa = {
"なし": 0x00,
"Ctrl": 0x01,
"Shift": 0x02,
"Ctrl+Shift": 0x03,
"Alt": 0x04,
"Ctrl+Alt": 0x05,
"Shift+Alt": 0x06,
"Ctrl+Shift+Alt": 0x07
};
const modifierCodesEn = {
"None": 0x00,
"Ctrl": 0x01,
"Shift": 0x02,
"Ctrl+Shift": 0x03,
"Alt": 0x04,
"Ctrl+Alt": 0x05,
"Shift+Alt": 0x06,
"Ctrl+Shift+Alt": 0x07
};
const consumerCodesJa = {
"なし": 0x00,
"再生": 0xB0,
"一時停止": 0xB1,
"録音": 0xB2,
"早送り": 0xB3,
"巻き戻し": 0xB4,
"次のトラック": 0xB5,
"前のトラック": 0xB6,
"停止": 0xB7,
"イジェクト": 0xB8,
"ランダム再生": 0xB9,
"不明 (0xE1)": 0xE1,
"音量ミュート": 0xE2,
"音量アップ": 0xE9,
"音量ダウン": 0xEA,
"システム電源": 0x30,
"システムリセット": 0x31,
"システムスリープ": 0x32,
"メニュー": 0x40,
"メニュー選択": 0x41,
"メニュー上": 0x42,
"メニュー下": 0x43,
"メニュー左": 0x44,
"メニュー右": 0x45,
"メニューエスケープ": 0x46,
"メニュー増加": 0x47,
"メニュー減少": 0x48
};
const consumerCodesEn = {
"None": 0x00,
"Play": 0xB0,
"Pause": 0xB1,
"Record": 0xB2,
"Fast Forward": 0xB3,
"Rewind": 0xB4,
"Next Track": 0xB5,
"Previous Track": 0xB6,
"Stop": 0xB7,
"Eject": 0xB8,
"Random Play": 0xB9,
"Unknown (0xE1)": 0xE1,
"Volume Mute": 0xE2,
"Volume Up": 0xE9,
"Volume Down": 0xEA,
"System Power": 0x30,
"System Reset": 0x31,
"System Sleep": 0x32,
"Menu": 0x40,
"Menu Pick": 0x41,
"Menu Up": 0x42,
"Menu Down": 0x43,
"Menu Left": 0x44,
"Menu Right": 0x45,
"Menu Escape": 0x46,
"Menu Increment": 0x47,
"Menu Decrement": 0x48
};
function getModifierCodes() {
return currentLang === 'ja' ? modifierCodesJa : modifierCodesEn;
}
function getConsumerCodes() {
return currentLang === 'ja' ? consumerCodesJa : consumerCodesEn;
}
function updateKeyType(keyNum) {
const type = document.getElementById(`key${keyNum}-type`).value;
const configDiv = document.getElementById(`key${keyNum}-config`);
if (type === "0") { // Keyboard key
configDiv.innerHTML = `
<div>
<h4>${t('toggleState1')}</h4>
<label>${t('modifier')}</label>
<select id="key${keyNum}-mod1">
${Object.entries(getModifierCodes()).map(([name, code]) =>
`<option value="${code}">${name}</option>`
).join('')}
</select><br>
<label>${t('keycode')}</label>
<select id="key${keyNum}-code1">
${Object.entries(keyboardCodes).sort((a, b) => {
if (a[0] === "なし" || a[0] === "None") return -1;
if (b[0] === "なし" || b[0] === "None") return 1;
return 0;
}).map(([name, code]) =>
`<option value="${code}" ${(name === "なし" || name === "None") ? "selected" : ""}>${name}</option>`
).join('')}
</select>
</div>
<div style="margin-top: 10px;">
<h4>${t('toggleState2')}</h4>
<label>${t('modifier')}</label>
<select id="key${keyNum}-mod2">
${Object.entries(getModifierCodes()).map(([name, code]) =>
`<option value="${code}">${name}</option>`
).join('')}
</select><br>
<label>${t('keycode')}</label>
<select id="key${keyNum}-code2">
${Object.entries(keyboardCodes).sort((a, b) => {
if (a[0] === "なし" || a[0] === "None") return -1;
if (b[0] === "なし" || b[0] === "None") return 1;
return 0;
}).map(([name, code]) =>
`<option value="${code}" ${(name === "なし" || name === "None") ? "selected" : ""}>${name}</option>`
).join('')}
</select>
</div>
<div class="modifier-info">
${t('toggleInfo')}
</div>
`;
} else if (type === "1") { // Consumer key
configDiv.innerHTML = `
<div>
<h4>${t('toggleState1')}</h4>
<label>${t('function')}:</label>
<select id="key${keyNum}-consumer1">
${Object.entries(getConsumerCodes()).sort((a, b) => {
if (a[0] === "なし" || a[0] === "None") return -1;
if (b[0] === "なし" || b[0] === "None") return 1;
return 0;
}).map(([name, code]) =>
`<option value="${code}" ${(name === "なし" || name === "None") ? "selected" : ""}>${name}</option>`
).join('')}
</select>
</div>
<div style="margin-top: 10px;">
<h4>${t('toggleState2')}</h4>
<label>${t('function')}:</label>
<select id="key${keyNum}-consumer2">
${Object.entries(getConsumerCodes()).sort((a, b) => {
if (a[0] === "なし" || a[0] === "None") return -1;
if (b[0] === "なし" || b[0] === "None") return 1;
return 0;
}).map(([name, code]) =>
`<option value="${code}" ${(name === "なし" || name === "None") ? "selected" : ""}>${name}</option>`
).join('')}
</select>
</div>
`;
} else if (type === "2") { // Macro key
configDiv.innerHTML = `
<div class="macro-keys">
<label>${t('macroCount')}:</label>
<input type="number" id="key${keyNum}-macro-count" min="1" max="10" value="3" onchange="updateMacroKeys(${keyNum})">
<div id="key${keyNum}-macro-keys" style="margin-top: 10px;"></div>
</div>
`;
updateMacroKeys(keyNum);
}
}
function updateMacroKeys(keyNum) {
const count = parseInt(document.getElementById(`key${keyNum}-macro-count`).value);
const macroDiv = document.getElementById(`key${keyNum}-macro-keys`);
let html = '';
for (let i = 0; i < count; i++) {
html += `
<div>
<label>${t('key')} ${i + 1}:</label>
<select id="key${keyNum}-macro${i}">
${Object.entries(keyboardCodes).sort((a, b) => {
if (a[0] === "なし" || a[0] === "None") return -1;
if (b[0] === "なし" || b[0] === "None") return 1;
return 0;
}).map(([name, code]) =>
`<option value="${code}" ${(name === "なし" || name === "None") ? "selected" : ""}>${name}</option>`
).join('')}
</select>
</div>
`;
}
macroDiv.innerHTML = html;
}
function generateEEPROM() {
let eepromData = new Array(128).fill(0xFF); // Initialize 128 bytes with 0xFF
for (let keyNum = 1; keyNum <= 6; keyNum++) {
const type = parseInt(document.getElementById(`key${keyNum}-type`).value);
const offset = (keyNum - 1) * 12; // Each key uses 12 bytes
eepromData[offset] = type;
if (type === 0) { // Keyboard key
eepromData[offset + 1] = parseInt(document.getElementById(`key${keyNum}-mod1`).value);
eepromData[offset + 2] = parseInt(document.getElementById(`key${keyNum}-code1`).value);
eepromData[offset + 3] = parseInt(document.getElementById(`key${keyNum}-mod2`).value);
eepromData[offset + 4] = parseInt(document.getElementById(`key${keyNum}-code2`).value);
} else if (type === 1) { // Consumer key
eepromData[offset + 1] = parseInt(document.getElementById(`key${keyNum}-consumer1`).value);
eepromData[offset + 2] = parseInt(document.getElementById(`key${keyNum}-consumer2`).value);
} else if (type === 2) { // Macro key
const count = parseInt(document.getElementById(`key${keyNum}-macro-count`).value);
eepromData[offset + 1] = count;
for (let i = 0; i < count && i < 10; i++) {
eepromData[offset + 2 + i] = parseInt(document.getElementById(`key${keyNum}-macro${i}`).value);
}
}
}
// Format output
let output = "EEPROM Data (128 bytes):\n\n";
output += "Address: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n";
output += "--------------------------------------------------------\n";
for (let i = 0; i < 128; i += 16) {
output += `0x${i.toString(16).padStart(2, '0').toUpperCase()}: `;
for (let j = 0; j < 16; j++) {
if (i + j < 128) {
output += eepromData[i + j].toString(16).padStart(2, '0').toUpperCase() + " ";
}
}
if (i < 72) {
output += ` // ${getKeyDescription(Math.floor(i / 12) + 1)}`;
}
output += "\n";
}
output += "\n\nC配列形式 (128 bytes):\n";
output += "const uint8_t eeprom_data[128] = {\n";
for (let i = 0; i < 128; i += 16) {
output += " ";
for (let j = 0; j < 16 && i + j < 128; j++) {
output += "0x" + eepromData[i + j].toString(16).padStart(2, '0').toUpperCase();
if (i + j < 127) output += ", ";
}
if (i < 112) output += ",";
if (i < 72) {
output += ` // ${getKeyDescription(Math.floor(i / 12) + 1)}`;
}
output += "\n";
}
output += "};\n";
document.getElementById('output').textContent = output;
globalEepromData = eepromData; // Store for download
}
function getKeyDescription(keyNum) {
const names = [t('key1'), t('key2'), t('key3'), t('encoderSwitch'), t('encoderCW'), t('encoderCCW')];
return names[keyNum - 1];
}
function copyToClipboard() {
const output = document.getElementById('output').textContent;
navigator.clipboard.writeText(output).then(() => {
alert(t('alertCopy'));
});
}
let globalEepromData = []; // Store EEPROM data globally for download
function downloadBinary() {
if (globalEepromData.length === 0) {
alert(t('alertGenerate'));
return;
}
// Create binary data
const buffer = new Uint8Array(globalEepromData);
const blob = new Blob([buffer], { type: 'application/octet-stream' });
// Create download link
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'macropad_eeprom.bin';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
function loadBinary(event) {
const file = event.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(e) {
const arrayBuffer = e.target.result;
const bytes = new Uint8Array(arrayBuffer);
if (bytes.length < 72) {
alert(t('alertSize'));
return;
}
// Parse the binary data and update UI
for (let keyNum = 1; keyNum <= 6; keyNum++) {
const offset = (keyNum - 1) * 12;
const type = bytes[offset];
// Set key type
document.getElementById(`key${keyNum}-type`).value = type;
updateKeyType(keyNum);
// Wait for DOM update
setTimeout(() => {
if (type === 0) { // Keyboard key
document.getElementById(`key${keyNum}-mod1`).value = bytes[offset + 1];
document.getElementById(`key${keyNum}-code1`).value = bytes[offset + 2];
document.getElementById(`key${keyNum}-mod2`).value = bytes[offset + 3];
document.getElementById(`key${keyNum}-code2`).value = bytes[offset + 4];
} else if (type === 1) { // Consumer key
document.getElementById(`key${keyNum}-consumer1`).value = bytes[offset + 1];
document.getElementById(`key${keyNum}-consumer2`).value = bytes[offset + 2];
} else if (type === 2) { // Macro key
const count = bytes[offset + 1];
document.getElementById(`key${keyNum}-macro-count`).value = count;
updateMacroKeys(keyNum);
// Wait for macro keys to be created
setTimeout(() => {
for (let i = 0; i < count && i < 10; i++) {
const macroSelect = document.getElementById(`key${keyNum}-macro${i}`);
if (macroSelect) {
macroSelect.value = bytes[offset + 2 + i];
}
}
}, 50);
}
}, 50);
}
alert(t('alertLoaded'));
};
reader.readAsArrayBuffer(file);
}
// Initialize all keys
for (let i = 1; i <= 6; i++) {
updateKeyType(i);
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment