ime bettter

This commit is contained in:
remi 2022-05-07 14:31:50 +02:00
parent be9fe1e3a3
commit 8095cae7cb

602
ime.js
View File

@ -1,167 +1,38 @@
let input = []; // bug: if you fuck up input really badly, you might get a ??? unicode to print.
// it successfully breaks everything. however, im not managing to repro it so...
// (shruggie)
let currentWord = []; let h;
let selected = -1;
window.onload = () => { window.onload = () => {
document.querySelectorAll(".ime").forEach(input => { document.querySelectorAll(".ime").forEach(input => {
input.addEventListener("keydown", (key) => { h = new HeonianIME();
imeDown(key, input); h.imeAttach(input);
});
input.addEventListener("mousedown", (e) => {
e.preventDefault();
input.focus();
imeUpdate(input);
})
}); });
} }
function imePush() { class HeonianIME {
//basically equavlient to pressing enter. constructor() {
if (selected == -1) { this.input = [];
if (currentWord.join() == "") { //blame js :) this.currentWord = [];
let s = document.createElement("p"); this.selected = -1;
s.innerText = input.join("");
document.body.appendChild(s);
input = [];
selected = -1;
} else {
input.push(currentWord);
currentWord = [];
}
imeReset();
} else {
if (selected+1 >= input.length) {
selected = -1;
} else {
selected += 1;
}
imeReset(true);
}
}
function imeDown(keyEvent, inputField) { this.inputState = 0; //STARTING, COMPOSTING, TRAILING, Fucking Nothing, ...cleanup
keyEvent.preventDefault(); this.stateState = 0; //depends on the state
switch (keyEvent.key) { this.inputFull = [];
case "Backspace": this.inputCurrent = "";
if (selected == -1) {
if (currentWord.join("") == "") {
currentWord = input.pop() || [];
} else {
imeRestore(currentWord);
// currentWord.pop();
}
} else {
imeRestore(input[selected]);
// input[selected].pop();
if (input[selected].join("") == "") {
input.splice(selected,1);
imeMove("left");
}
}
break;
case "Enter":
imePush()
break;
case "Space":
//adds a ', on second press . an actual space
break;
case "ArrowLeft":
imeMove("left");
break;
case "ArrowRight":
imeMove("right");
break;
case "ArrowDown":
imeMove("start");
break;
case "ArrowUp":
imeMove("end");
break;
default:
imeInput(keyEvent.key);
if (selected == -1) {
currentWord = inputFull;
} else {
input[selected] = inputFull;
}
break;
}
imeUpdate(inputField);
}
function imeUpdate(inputField) { this.ourHtml;
let renderText = "";
input.forEach((w) => {
renderText += w.join("");
})
inputField.value = renderText + currentWord.join("");
if (selected == -1) {
inputField.setSelectionRange(renderText.length, renderText.length+currentWord.join("").length);
} else {
from = 0;
for (let x = 0; x < selected; x++) {
from += input[x].join("").length;
}
to = from+input[selected].join("").length;
inputField.setSelectionRange(from, to);
}
}
function clamp(min, max, value) { this.hVowels = { //standalone, composing, trailing
return Math.max(min, Math.min(max, value));
}
function imeMove(direction) {
let d = 1;
if (currentWord.join("") != "") {
input.push(currentWord);
currentWord = [];
d = 2;
}
switch (direction) {
case "start":
selected = 0;
break;
case "end":
selected = -1;
break;
case "left":
if (selected == -1) selected = input.length;
selected -= 1 * d;
if (selected != -1) {
selected = clamp(0,input.length,selected);
//is there even a point in clamping it here,,,,
}
break;
case "right":
selected += 1 * d;
selected = clamp(0,input.length,selected);
//tbh same here, like.
//oh well ig ???/
if (selected == input.length) {
selected = -1;
}
break;
}
imeReset(true);
}
let inputState = 0; //STARTING, COMPOSTING, TRAILING, Fucking Nothing, ...cleanup
let stateState = 0; //depends on the state
let inputFull = [];
let inputCurrent = "";
let hVowels = { //standalone, composing, trailing
"a": ["0", "5", "A"], "a": ["0", "5", "A"],
"e": ["1", "6", "B"], "e": ["1", "6", "B"],
"i": ["2", "7", "C"], "i": ["2", "7", "C"],
"o": ["3", "8", "D"], "o": ["3", "8", "D"],
"u": ["4", "9", "E"] "u": ["4", "9", "E"]
}; };
let hConsonants = { //0 = standalone, 1 = composing, 2-6 = vowels this.hConsonants = { //0 = standalone, 1 = composing, 2-6 = vowels
"g": "01", "g": "01",
"s": "02", "s": "02",
"r": "03", "r": "03",
@ -178,257 +49,410 @@ let hConsonants = { //0 = standalone, 1 = composing, 2-6 = vowels
"b": "0E", "b": "0E",
"d": "0F", "d": "0F",
"h": "10", "h": "10",
}; };
function getUnicodeVowel(vowel, sot) { this.hVowelsK = Object.keys(this.hVowels)
this.hConsonantsK = Object.keys(this.hConsonants);
this.hConsonantsR = this.inverse(this.hConsonants);
}
imeAttach(what) { //re-attaching is unsupported :3
this.ourHtml = what;
what.addEventListener("keydown", (key) => {
this.imeDown(key, what);
});
what.addEventListener("mousedown", (e) => {
this.mouse(e, what);
});
}
mouse(e, what) {
e.preventDefault();
what.focus();
this.imeUpdate(what);
}
imeDetach() {
//how do we detach this without . uh,
this.imeDown = ()=>{};
this.mouse = ()=>{};
//close enough?
}
imePush() {
//basically equavlient to pressing enter.
if (this.selected == -1) {
if (this.currentWord.join() == "") { //blame js :)
let s = document.createElement("p");
s.innerText = this.input.join("");
document.body.appendChild(s);
this.input = [];
this.selected = -1;
} else {
this.input.push(this.currentWord);
this.currentWord = [];
}
this.imeReset();
} else {
if (this.selected + 1 >= this.input.length) {
this.selected = -1;
} else {
this.selected += 1;
}
this.imeReset(true);
}
}
imeDown(keyEvent, inputField) {
keyEvent.preventDefault();
switch (keyEvent.key) {
case "Backspace":
if (this.selected == -1) {
if (this.currentWord.join("") == "") {
this.currentWord = this.input.pop() || [];
} else {
this.imeRestore(this.currentWord);
// this.currentWord.pop();
}
} else {
this.imeRestore(this.input[this.selected]);
// this.input[this.selected].pop();
if (this.input[this.selected].join("") == "") {
this.input.splice(this.selected, 1);
this.imeMove("left");
}
}
break;
case "Enter":
this.imePush()
break;
case "Space":
//adds a ', on second press . an actual space
break;
case "ArrowLeft":
this.imeMove("left");
break;
case "ArrowRight":
this.imeMove("right");
break;
case "ArrowDown":
this.imeMove("start");
break;
case "ArrowUp":
this.imeMove("end");
break;
case "Escape":
this.imeDetach();
break;
default:
this.imeInput(keyEvent.key);
if (this.selected == -1) {
this.currentWord = this.inputFull;
} else {
this.input[this.selected] = this.inputFull;
}
break;
}
this.imeUpdate(inputField);
}
imeUpdate(inputField) {
let renderText = "";
this.input.forEach((w) => {
renderText += w.join("");
})
inputField.value = renderText + this.currentWord.join("");
if (this.selected == -1) {
inputField.setSelectionRange(renderText.length, renderText.length + this.currentWord.join("").length);
} else {
if (this.input.join("") != "") {
let from = 0;
for (let x = 0; x < this.selected; x++) {
from += this.input[x].join("").length;
}
let to = from + this.input[this.selected].join("").length;
inputField.setSelectionRange(from, to);
}
}
}
clamp(min, max, value) {
return Math.max(min, Math.min(max, value));
}
imeMove(direction) {
let d = 1;
if (this.currentWord.join("") != "") {
this.input.push(this.currentWord);
this.currentWord = [];
d = 2;
}
switch (direction) {
case "start":
this.selected = 0;
break;
case "end":
this.selected = -1;
break;
case "left":
if (this.selected == -1) this.selected = this.input.length;
this.selected -= 1 * d;
if (this.selected != -1) {
this.selected = this.clamp(0, this.input.length, this.selected);
//is there even a point in clamping it here,,,,
}
break;
case "right":
this.selected += 1 * d;
this.selected = this.clamp(0, this.input.length, this.selected);
//tbh same here, like.
//oh well ig ???/
if (this.selected == this.input.length) {
this.selected = -1;
}
break;
}
this.imeReset(true);
}
getUnicodeVowel(vowel, sot) {
if (sot == "standalone") sot = 0; if (sot == "standalone") sot = 0;
if (sot == "composing") sot = 1; if (sot == "composing") sot = 1;
if (sot == "trailing") sot = 2; if (sot == "trailing") sot = 2;
return String.fromCharCode(parseInt("E00" + hVowels[vowel][sot], 16)); return String.fromCharCode(parseInt("E00" + this.hVowels[vowel][sot], 16));
} }
function getUnicodeConsonant(consonant, scv) { getUnicodeConsonant(consonant, scv) {
if (scv == "standalone") {scv = 0;} if (scv == "standalone") { scv = 0; }
else if (scv == "trailing") {scv = 1;} else if (scv == "trailing") { scv = 1; }
else {scv = Number(hVowels[scv][0])+2} else {
return String.fromCharCode(parseInt("E" + hConsonants[consonant] + "" + scv, 16)); scv = Number(this.hVowels[scv][0]) + 2
} }
return String.fromCharCode(parseInt("E" + this.hConsonants[consonant] + "" + scv, 16));
}
function inverse(obj){ inverse(obj) {
var retobj = {}; var retobj = {};
for(var key in obj){ for (var key in obj) {
retobj[obj[key]] = key; retobj[obj[key]] = key;
} }
return retobj; return retobj;
} }
let hVowelsK = Object.keys(hVowels) imeReset(soft = false) {
let hConsonantsK = Object.keys(hConsonants); this.stateState = 0;
let hConsonantsR = inverse(hConsonants); this.inputState = 0;
this.inputFull = [];
function debugInput(key) { this.inputCurrent = "";
console.log("pre "+key+": inputstate - "+inputState +", statestate - "+ stateState);
console.log("inputfull: " + inputFull.join(" ") + ", inputcurrent:" + inputCurrent);
imeInput(key);
console.log("post "+key+": inputstate - "+inputState +", statestate - "+ stateState);
console.log("inputfull: " + inputFull.join(" ") + ", inputcurrent:" + inputCurrent);
console.log("------------------------------")
}
function imeReset(soft = false) {
stateState = 0;
inputState = 0;
inputFull = [];
inputCurrent = "";
if (!soft) { if (!soft) {
if (selected == -1) { if (this.selected == -1) {
currentWord = []; this.currentWord = [];
} else { } else {
input[selected] = []; this.input[this.selected] = [];
}
} }
} }
}
function imeInfo(decHex) { imeInfo(decHex) {
try { try {
let hex = decHex.codePointAt(0).toString(16); let hex = decHex.codePointAt(0).toString(16).split("");
hex[1] = parseInt(hex[1], 16); hex[1] = hex[1].toString(16);//parseInt(hex[1], 16);
hex[2] = parseInt(hex[2], 16); hex[2] = hex[2].toString(16);//parseInt(hex[2], 16);
hex[3] = parseInt(hex[3], 16); hex[3] = hex[3].toString(16);//parseInt(hex[3], 16);
let ka = (hex[1] == 0 && hex[2] == 0) ? "a" : "k"; let ka = (hex[1] == 0 && hex[2] == 0) ? "a" : "k";
if (ka == "k") { if (ka == "k") {
if (hex[3] == 1) { if (hex[3] == 1) {
//trailing //trailing
return([ka,"trailing"]) return ([ka, "trailing"])
} else if (hex[3] == 0) { } else if (hex[3] == 0) {
//standalone //standalone
//full reset / no restore necessary //full reset / no restore necessary
return([ka,"standalone"]) return ([ka, "standalone"])
} else { } else {
//composing //composing
return([ka,"composing"]) return ([ka, "composing"])
} }
} else { } else {
if (hex[3] <= 8) { if (hex[3] <= 8) {
//standalone //standalone
return([ka,"standalone"]) return ([ka, "standalone"])
} else { } else {
//trailing //trailing
return([ka,"trailing"]) return ([ka, "trailing"])
} }
} }
} catch { } catch {
return ""; return "";
} }
} }
function imeChange(inState, stState, pop, array) { imeChange(inState, stState, pop, array) {
inputState = inState; this.inputState = inState;
stateState = stState; this.stateState = stState;
if (pop) { if (pop) {
array.pop(); array.pop();
} }
inputFull = array; this.inputFull = array;
} }
// @remi@snug.moe: // @remi@snug.moe:
// we made a backspace key that works!!!!!!! // we made a backspace key that works!!!!!!!
// @meduelelateta@sweet.succubi.services: // @meduelelateta@sweet.succubi.services:
// ari fell asleep // ari fell asleep
function imeRestore(array) { imeRestore(array) {
let hex = array[array.length-1].codePointAt(0).toString(16); let hex = array[array.length - 1].codePointAt(0).toString(16).split("");
hex[1] = parseInt(hex[1], 16); hex[1] = hex[1].toString(16);//parseInt(hex[1], 16);
hex[2] = parseInt(hex[2], 16); hex[2] = hex[2].toString(16);//parseInt(hex[2], 16);
hex[3] = parseInt(hex[3], 16); hex[3] = hex[3].toString(16);//parseInt(hex[3], 16);
let previous = imeInfo(array[array.length-2])[1]; let previous = this.imeInfo(array[array.length - 2])[1];
let ka = (hex[1] == 0 && hex[2] == 0) ? "a" : "k"; let ka = (hex[1] == 0 && hex[2] == 0) ? "a" : "k";
if (ka == "k") { if (ka == "k") {
if (hex[3] == 1) { if (hex[3] == 1) {
//trailing //trailing
if (previous == "trailing") { if (previous == "trailing") {
//trailing twice //trailing twice
console.log("2.1"); // console.log("2.1");
imeChange(2,1,true,array); this.imeChange(2, 1, true, array);
} else { } else {
//trailing once //trailing once
console.log("2.0"); // console.log("2.0");
imeChange(2,0,true,array); this.imeChange(2, 0, true, array);
} }
} else if (hex[3] == 0) { } else if (hex[3] == 0) {
console.log(array.length);
if (array.length != 1) { if (array.length != 1) {
//0.1, i think? //0.1, i think?
console.log("0.1"); // console.log("0.1");
imeChange(0,1,true,array); this.imeChange(0, 1, true, array);
} else { } else {
//standalone //standalone
console.log("full reset"); // console.log("full reset");
imeReset(); this.imeReset();
} }
} else { } else {
//composing //composing
if (previous == "standalone") { if (previous == "standalone") {
//0.1?? //0.1??
//recreate?? last digit??? //recreate?? last digit???
let c = hConsonantsR[[hex[1], hex[2]].join("").toUpperCase()]; let c = this.hConsonantsR[[hex[1], hex[2]].join("").toUpperCase()];
array.pop(); array.pop();
array.push(getUnicodeConsonant(c, "standalone")); array.push(this.getUnicodeConsonant(c, "standalone"));
inputCurrent = c; this.inputCurrent = c;
console.log("0.1"); // console.log("0.1");
imeChange(0,1,false,array); this.imeChange(0, 1, false, array);
} else { } else {
//0.2???? fuck it lets try and find out ig //0.2???? fuck it lets try and find out ig
//recreate?? last digit??? //recreate?? last digit???
let c = hConsonantsR[[hex[1], hex[2]].join("").toUpperCase()]; let c = this.hConsonantsR[[hex[1], hex[2]].join("").toUpperCase()];
array.pop(); array.pop();
array.push(getUnicodeConsonant(c, "standalone")); array.push(this.getUnicodeConsonant(c, "standalone"));
inputCurrent = c; this.inputCurrent = c;
console.log("0.2"); // console.log("0.2");
imeChange(0,2,false,array); this.imeChange(0, 2, false, array);
} }
} }
} else { } else {
if (hex[3] <= 8) { if (hex[3] <= 8) {
//standalone //standalone
console.log("full reset"); // console.log("full reset");
imeReset(); this.imeReset();
} else { } else {
//trailing //trailing
if (previous == "trailing") { if (previous == "trailing") {
//trailing twice //trailing twice
console.log("2.1"); // console.log("2.1");
imeChange(2,1,true,array); this.imeChange(2, 1, true, array);
} else { } else {
//trailing once //trailing once
console.log("2.0"); // console.log("2.0");
imeChange(2,0,true,array); this.imeChange(2, 0, true, array);
}
} }
} }
} }
}
function imeInput(key) { imeInput(key) {
key = key.toLowerCase(); key = key.toLowerCase();
if (!hConsonantsK.includes(key) && !hVowelsK.includes(key)) return; if (!this.hConsonantsK.includes(key) && !this.hVowelsK.includes(key)) return;
switch (inputState) { switch (this.inputState) {
case 0: //starting case 0: //starting
if (stateState == 0) { if (this.stateState == 0) {
if (hVowelsK.includes(key)) { if (this.hVowelsK.includes(key)) {
inputFull.push(getUnicodeVowel(key, "standalone")); this.inputFull.push(this.getUnicodeVowel(key, "standalone"));
inputState = 2; this.inputState = 2;
} else { } else {
inputFull.push(getUnicodeConsonant(key, "standalone")); this.inputFull.push(this.getUnicodeConsonant(key, "standalone"));
stateState = 1; this.stateState = 1;
inputCurrent = key; this.inputCurrent = key;
} }
break; break;
} else if (stateState == 1) { } else if (this.stateState == 1) {
if (hVowelsK.includes(key)) { if (this.hVowelsK.includes(key)) {
inputState = 1; this.inputState = 1;
stateState = 0; this.stateState = 0;
} else { } else {
inputFull.push(getUnicodeConsonant(key, "trailing")); this.inputFull.push(this.getUnicodeConsonant(key, "trailing"));
inputCurrent = key; this.inputCurrent = key;
stateState = 2; this.stateState = 2;
break; break;
} }
} else if (stateState == 2) { } else if (this.stateState == 2) {
if (hVowelsK.includes(key)) { if (this.hVowelsK.includes(key)) {
inputState = 1; this.inputState = 1;
stateState = 0; this.stateState = 0;
} else break; } else break;
} }
case 1: //composing case 1: //composing
if (hVowelsK.includes(key)) { if (this.hVowelsK.includes(key)) {
inputState = 2; this.inputState = 2;
inputFull.pop(); this.inputFull.pop();
inputFull.push(getUnicodeConsonant(inputCurrent, key)); this.inputFull.push(this.getUnicodeConsonant(this.inputCurrent, key));
inputCurrent = ""; this.inputCurrent = "";
} }
break; break;
case 2: //trailing case 2: //trailing
if (hVowelsK.includes(key)) { if (this.hVowelsK.includes(key)) {
if (stateState == 1 && inputCurrent != "") { if (this.stateState == 1 && this.inputCurrent != "") {
inputFull.pop(); this.inputFull.pop();
let ic = inputCurrent; let ic = this.inputCurrent;
let k = key; let k = key;
imePush(); this.imePush();
inputFull.pop(); this.inputFull.pop();
inputFull.push(getUnicodeConsonant(ic, k)); this.inputFull.push(this.getUnicodeConsonant(ic, k));
inputCurrent = ""; this.inputCurrent = "";
inputState = 2; this.inputState = 2;
} else { } else {
inputFull.push(getUnicodeVowel(key, "trailing")); this.inputFull.push(this.getUnicodeVowel(key, "trailing"));
inputCurrent = ""; this.inputCurrent = "";
stateState += 1; this.stateState += 1;
} }
} else { } else {
inputFull.push(getUnicodeConsonant(key, "trailing")); this.inputFull.push(this.getUnicodeConsonant(key, "trailing"));
inputCurrent = key; this.inputCurrent = key;
stateState += 1; this.stateState += 1;
} }
if (stateState == 2) { if (this.stateState == 2) {
stateState = 0; this.stateState = 0;
inputState = 3; this.inputState = 3;
}; };
break; break;
case 3: //go to next word uwu case 3: //go to next word uwu
if (key != "") { if (this.hVowelsK.includes(key)) {
inputFull.pop(); this.inputFull.pop();
let ic = inputCurrent; let ic = this.inputCurrent;
let k = key; let k = key;
imePush(); this.imePush();
inputFull.pop(); this.inputFull.pop();
inputFull.push(getUnicodeConsonant(ic, k)); this.inputFull.push(this.getUnicodeConsonant(ic, k));
inputCurrent = ""; this.inputCurrent = "";
inputState = 2; this.inputState = 2;
} else { } else {
imePush(); this.imePush();
imeInput(key); this.imeInput(key);
} }
break; break;
} }
}
} }