Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 277c4689d5 | |||
| dbe046a194 | |||
| 02e68dc1c7 | |||
| 9c61531820 | |||
| 67bac6f486 |
+128
-47
@@ -213,7 +213,7 @@
|
|||||||
<input id="input" class="hidden-input" type="text" autocomplete="off" aria-hidden="true" tabindex="-1">
|
<input id="input" class="hidden-input" type="text" autocomplete="off" aria-hidden="true" tabindex="-1">
|
||||||
|
|
||||||
<div class="input-row">
|
<div class="input-row">
|
||||||
<div class="hint">Keyboard input is captured directly by the screen</div>
|
<div class="hint">Keyboard works globally: digits, numpad, Enter, Backspace, Delete, →, +, -, *, /, %, ^, q, n, r, i, g, l, s, c, t, S, C, T</div>
|
||||||
<select id="angleMode">
|
<select id="angleMode">
|
||||||
<option value="deg">Degrees</option>
|
<option value="deg">Degrees</option>
|
||||||
<option value="rad">Radians</option>
|
<option value="rad">Radians</option>
|
||||||
@@ -286,14 +286,18 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getStackValue(index) {
|
||||||
|
return calc.isValidIndex(index) ? calc.stack[index] : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
function getLineValue(line) {
|
function getLineValue(line) {
|
||||||
if (calc.isEditing) {
|
if (calc.isEditing) {
|
||||||
if (line === 0) {
|
if (line === 0) {
|
||||||
return calc.inputValue;
|
return calc.inputValue;
|
||||||
}
|
}
|
||||||
return calc.stack[line - 1];
|
return getStackValue(line - 1);
|
||||||
}
|
}
|
||||||
return calc.stack[line];
|
return getStackValue(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
@@ -317,11 +321,7 @@
|
|||||||
if (!calc.isEditing) return;
|
if (!calc.isEditing) return;
|
||||||
if (calc.inputValue !== '') {
|
if (calc.inputValue !== '') {
|
||||||
const value = calc.parseInputValue(calc.inputValue);
|
const value = calc.parseInputValue(calc.inputValue);
|
||||||
if (calc.stack.length >= calc.maxSize) {
|
calc.push(value);
|
||||||
throw new Error('Stack overflow');
|
|
||||||
}
|
|
||||||
calc.stack.unshift(value);
|
|
||||||
if (calc.stack.length > 4) calc.stack.length = 4;
|
|
||||||
}
|
}
|
||||||
calc.inputValue = '';
|
calc.inputValue = '';
|
||||||
calc.isEditing = false;
|
calc.isEditing = false;
|
||||||
@@ -330,18 +330,20 @@
|
|||||||
|
|
||||||
function execute(name) {
|
function execute(name) {
|
||||||
try {
|
try {
|
||||||
if (name === 'swap') {
|
if (name === 'enter') {
|
||||||
pushEditingValueIfNeeded();
|
|
||||||
if (calc.stack.length >= 2) calc.swap(0, 1);
|
|
||||||
} else if (name === 'drop') {
|
|
||||||
pushEditingValueIfNeeded();
|
|
||||||
if (calc.stack.length >= 1) calc.remove(0);
|
|
||||||
} else if (name === 'clear') {
|
|
||||||
calc.clear();
|
|
||||||
} else if (name === 'enter') {
|
|
||||||
if (calc.isEditing) {
|
if (calc.isEditing) {
|
||||||
pushEditingValueIfNeeded();
|
pushEditingValueIfNeeded();
|
||||||
|
} else if (calc.isValidIndex(0)) {
|
||||||
|
calc.push(getStackValue(0));
|
||||||
}
|
}
|
||||||
|
} else if (name === 'swap') {
|
||||||
|
pushEditingValueIfNeeded();
|
||||||
|
if (calc.isValidIndex(1)) calc.swap(0, 1);
|
||||||
|
} else if (name === 'drop') {
|
||||||
|
pushEditingValueIfNeeded();
|
||||||
|
if (calc.isValidIndex(0)) calc.remove(0);
|
||||||
|
} else if (name === 'clear') {
|
||||||
|
calc.clear();
|
||||||
} else {
|
} else {
|
||||||
pushEditingValueIfNeeded();
|
pushEditingValueIfNeeded();
|
||||||
calc.command(name);
|
calc.command(name);
|
||||||
@@ -354,7 +356,77 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isInputChar(key) {
|
function isInputChar(key) {
|
||||||
return /^[0-9a-fA-F.+\-]$/.test(key);
|
return /^[0-9a-fA-F.]$/.test(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function shouldIgnoreKeyboardEvent(event) {
|
||||||
|
const target = event.target;
|
||||||
|
if (!target) return false;
|
||||||
|
|
||||||
|
const tagName = target.tagName;
|
||||||
|
return (
|
||||||
|
tagName === 'INPUT' ||
|
||||||
|
tagName === 'TEXTAREA' ||
|
||||||
|
tagName === 'SELECT' ||
|
||||||
|
target.isContentEditable
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getKeyboardAction(event) {
|
||||||
|
const numpadMap = {
|
||||||
|
Numpad0: { type: 'input', value: '0' },
|
||||||
|
Numpad1: { type: 'input', value: '1' },
|
||||||
|
Numpad2: { type: 'input', value: '2' },
|
||||||
|
Numpad3: { type: 'input', value: '3' },
|
||||||
|
Numpad4: { type: 'input', value: '4' },
|
||||||
|
Numpad5: { type: 'input', value: '5' },
|
||||||
|
Numpad6: { type: 'input', value: '6' },
|
||||||
|
Numpad7: { type: 'input', value: '7' },
|
||||||
|
Numpad8: { type: 'input', value: '8' },
|
||||||
|
Numpad9: { type: 'input', value: '9' },
|
||||||
|
NumpadDecimal: { type: 'input', value: '.' },
|
||||||
|
NumpadAdd: { type: 'command', value: 'add' },
|
||||||
|
NumpadSubtract: { type: 'command', value: 'sub' },
|
||||||
|
NumpadMultiply: { type: 'command', value: 'mul' },
|
||||||
|
NumpadDivide: { type: 'command', value: 'div' },
|
||||||
|
NumpadEnter: { type: 'command', value: 'enter' },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (numpadMap[event.code]) {
|
||||||
|
return numpadMap[event.code];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isInputChar(event.key)) {
|
||||||
|
return { type: 'input', value: event.key };
|
||||||
|
}
|
||||||
|
|
||||||
|
const keyMap = {
|
||||||
|
Enter: { type: 'command', value: 'enter' },
|
||||||
|
Backspace: { type: 'stackOrEdit', value: 'drop' },
|
||||||
|
Delete: { type: 'command', value: 'clear' },
|
||||||
|
Escape: { type: 'cancelEdit' },
|
||||||
|
ArrowRight: { type: 'command', value: 'swap' },
|
||||||
|
'+': { type: 'command', value: 'add' },
|
||||||
|
'-': { type: 'command', value: 'sub' },
|
||||||
|
'*': { type: 'command', value: 'mul' },
|
||||||
|
'/': { type: 'command', value: 'div' },
|
||||||
|
'%': { type: 'command', value: 'mod' },
|
||||||
|
'^': { type: 'command', value: 'pow' },
|
||||||
|
q: { type: 'command', value: 'sqr' },
|
||||||
|
n: { type: 'command', value: 'neg' },
|
||||||
|
r: { type: 'command', value: 'sqrt' },
|
||||||
|
i: { type: 'command', value: 'recip' },
|
||||||
|
g: { type: 'command', value: 'log' },
|
||||||
|
l: { type: 'command', value: 'ln' },
|
||||||
|
s: { type: 'command', value: 'sin' },
|
||||||
|
c: { type: 'command', value: 'cos' },
|
||||||
|
t: { type: 'command', value: 'tan' },
|
||||||
|
S: { type: 'command', value: 'asin' },
|
||||||
|
C: { type: 'command', value: 'acos' },
|
||||||
|
T: { type: 'command', value: 'atan' },
|
||||||
|
};
|
||||||
|
|
||||||
|
return keyMap[event.key] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function focusScreen() {
|
function focusScreen() {
|
||||||
@@ -382,47 +454,56 @@
|
|||||||
syncInputFromState();
|
syncInputFromState();
|
||||||
}
|
}
|
||||||
|
|
||||||
screen.addEventListener('keydown', (event) => {
|
function handleKeydown(event) {
|
||||||
|
if (shouldIgnoreKeyboardEvent(event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const action = getKeyboardAction(event);
|
||||||
|
if (!action) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (event.key === 'Enter') {
|
if (action.type === 'cancelEdit') {
|
||||||
event.preventDefault();
|
if (!calc.isEditing) {
|
||||||
execute('enter');
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.key === 'Backspace') {
|
|
||||||
event.preventDefault();
|
|
||||||
if (calc.isEditing) {
|
|
||||||
editXWithKey('Backspace');
|
|
||||||
render();
|
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isInputChar(event.key)) {
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
editXWithKey(event.key);
|
calc.inputValue = '';
|
||||||
|
calc.isEditing = false;
|
||||||
|
syncInputFromState();
|
||||||
render();
|
render();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keyMap = {
|
event.preventDefault();
|
||||||
'+': 'add',
|
|
||||||
'-': 'sub',
|
|
||||||
'*': 'mul',
|
|
||||||
'/': 'div',
|
|
||||||
'%': 'mod',
|
|
||||||
'^': 'pow',
|
|
||||||
};
|
|
||||||
|
|
||||||
if (keyMap[event.key]) {
|
if (action.type === 'input') {
|
||||||
event.preventDefault();
|
editXWithKey(action.value);
|
||||||
execute(keyMap[event.key]);
|
render();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.type === 'stackOrEdit') {
|
||||||
|
if (calc.isEditing) {
|
||||||
|
editXWithKey('Backspace');
|
||||||
|
render();
|
||||||
|
} else {
|
||||||
|
execute(action.value);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.type === 'command') {
|
||||||
|
execute(action.value);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
errorEl.textContent = error.message;
|
errorEl.textContent = error.message;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
window.addEventListener('keydown', handleKeydown);
|
||||||
|
|
||||||
screen.addEventListener('click', focusScreen);
|
screen.addEventListener('click', focusScreen);
|
||||||
window.addEventListener('load', focusScreen);
|
window.addEventListener('load', focusScreen);
|
||||||
|
|||||||
Reference in New Issue
Block a user