Hiển thị duy nhất cụm phím ảo điều khiển di chuyển (WASD + Space) trên màn hình minefun.io. Ấn phím [ . ] để mở menu cài đặt màu sắc và vị trí.
// ==UserScript==
// @name Minefun Simple Virtual Keyboard
// @namespace http://tampermonkey.net
// @version 1.1
// @description Hiển thị duy nhất cụm phím ảo điều khiển di chuyển (WASD + Space) trên màn hình minefun.io. Ấn phím [ . ] để mở menu cài đặt màu sắc và vị trí.
// @author AI Assistant
// @match https://minefun.io*
// @license MIT
// @grant none
// ==/UserScript==
(function() {
'use strict';
// --- 1. TẠO GIAO DIỆN BÀN PHÍM ẢO DI CHUYỂN ---
const kbContainer = document.createElement('div');
kbContainer.id = 'virtual-keyboard';
kbContainer.style.cssText = `
position: fixed;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.7);
padding: 12px;
border-radius: 10px;
z-index: 99999;
display: flex;
flex-direction: column;
gap: 6px;
user-select: none;
box-shadow: 0 4px 15px rgba(0,0,0,0.5);
`;
// Cấu trúc chỉ gồm cụm phím di chuyển cơ bản
const rows = [
['W'],
['A', 'S', 'D'],
['Space']
];
rows.forEach(rowKeys => {
const rowDiv = document.createElement('div');
rowDiv.style.cssText = 'display: flex; justify-content: center; gap: 6px;';
rowKeys.forEach(key => {
const keyBtn = document.createElement('div');
keyBtn.innerText = key === 'Space' ? 'SPACE' : key;
keyBtn.className = 'kb-key';
keyBtn.dataset.key = key.toLowerCase();
// Kiểu dáng tối giản cho phím ảo
keyBtn.style.cssText = `
width: ${key === 'Space' ? '150px' : '45px'};
height: 45px;
background: #2a2a2a;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
font-size: 14px;
border-radius: 6px;
border: 1px solid #444;
font-family: 'Segoe UI', Arial, sans-serif;
transition: background 0.1s, transform 0.1s, opacity 0.1s;
`;
rowDiv.appendChild(keyBtn);
});
kbContainer.appendChild(rowDiv);
});
document.body.appendChild(kbContainer);
// --- 2. MENU ĐIỀU CHỈNH (ẨN/HIỆN BẰNG PHÍM DẤU CHẤM) ---
const menu = document.createElement('div');
menu.style.cssText = `
position: fixed;
top: 25%;
left: 50%;
transform: translate(-50%, -25%);
background: #1e1e1e;
color: #fff;
padding: 20px;
border-radius: 12px;
border: 1px solid #444;
z-index: 100000;
display: none;
flex-direction: column;
gap: 15px;
font-family: 'Segoe UI', Arial, sans-serif;
box-shadow: 0 10px 25px rgba(0,0,0,0.7);
width: 240px;
`;
menu.innerHTML = `
<h4 style="margin: 0 0 5px 0; text-align: center; font-size: 16px; color: #4caf50;">Cài Đặt Bàn Phím Vỏ</h4>
<label style="display: flex; justify-content: space-between; align-items: center; font-size: 14px;">
Màu nút:
<input type="color" id="key-color-picker" value="#2a2a2a" style="border:none; background:none; cursor:pointer;">
</label>
<label style="display: flex; justify-content: space-between; align-items: center; font-size: 14px;">
Màu chữ:
<input type="color" id="text-color-picker" value="#ffffff" style="border:none; background:none; cursor:pointer;">
</label>
<div style="border-top: 1px solid #333; padding-top: 10px;">
<p style="margin: 0 0 8px 0; font-size: 13px; color: #aaa;">Di chuyển vị trí:</p>
<div style="display: flex; gap: 4px; justify-content: space-between;">
<button id="move-left" style="flex:1; padding: 6px; background:#333; color:#fff; border:1px solid #555; border-radius:4px; cursor:pointer;">Trái</button>
<button id="move-right" style="flex:1; padding: 6px; background:#333; color:#fff; border:1px solid #555; border-radius:4px; cursor:pointer;">Phải</button>
<button id="move-up" style="flex:1; padding: 6px; background:#333; color:#fff; border:1px solid #555; border-radius:4px; cursor:pointer;">Lên</button>
<button id="move-down" style="flex:1; padding: 6px; background:#333; color:#fff; border:1px solid #555; border-radius:4px; cursor:pointer;">Xuống</button>
</div>
</div>
<p style="margin: 5px 0 0 0; font-size: 11px; color: #777; text-align: center;">Ấn phím [ . ] để đóng menu này</p>
`;
document.body.appendChild(menu);
// --- 3. LOGIC HOẠT ĐỘNG ---
// Nhấn phím "." để mở menu
window.addEventListener('keydown', (e) => {
if (e.key === '.') {
if (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA') return;
e.preventDefault();
menu.style.display = menu.style.display === 'none' ? 'flex' : 'none';
}
});
// Đồng bộ sáng/tối khi bạn bấm phím thật
const toggleHighlight = (keyStr, isPressed) => {
let targetKey = keyStr.toLowerCase();
if (targetKey === ' ') targetKey = 'space';
const keyVisual = kbContainer.querySelector(`.kb-key[data-key="${targetKey}"]`);
if (keyVisual) {
keyVisual.style.opacity = isPressed ? '0.5' : '1';
keyVisual.style.transform = isPressed ? 'scale(0.92)' : 'scale(1)';
}
};
window.addEventListener('keydown', (e) => toggleHighlight(e.key, true));
window.addEventListener('keyup', (e) => toggleHighlight(e.key, false));
// Đổi màu sắc từ Menu
menu.querySelector('#key-color-picker').addEventListener('input', (e) => {
kbContainer.querySelectorAll('.kb-key').forEach(k => k.style.background = e.target.value);
});
menu.querySelector('#text-color-picker').addEventListener('input', (e) => {
kbContainer.querySelectorAll('.kb-key').forEach(k => k.style.color = e.target.value);
});
// Di chuyển cụm phím ảo độc lập bằng nút trong menu
let currentLeft = window.innerWidth / 2;
let currentBottom = 30;
kbContainer.style.transform = 'none';
kbContainer.style.left = `${currentLeft - 85}px`;
const moveStep = 25;
menu.querySelector('#move-left').addEventListener('click', () => { currentLeft -= moveStep; kbContainer.style.left = `${currentLeft}px`; });
menu.querySelector('#move-right').addEventListener('click', () => { currentLeft += moveStep; kbContainer.style.left = `${currentLeft}px`; });
menu.querySelector('#move-up').addEventListener('click', () => { currentBottom += moveStep; kbContainer.style.bottom = `${currentBottom}px`; });
menu.querySelector('#move-down').addEventListener('click', () => { currentBottom -= moveStep; kbContainer.style.bottom = `${currentBottom}px`; });
})();