From 47d3da76aaaba41ea10fe4d07e4def0692003747 Mon Sep 17 00:00:00 2001 From: Saamkhaih Kyakya <70475761+hiohlan@users.noreply.github.com> Date: Thu, 28 Dec 2023 01:54:25 +0700 Subject: [PATCH 1/4] feat: added support for ChromeOS remap, fix: typo local genKlc --- README.md | 1 + cli.ts | 20 +++ generateChr_background.ts | 192 ++++++++++++++++++++++++ generateChr_manifest.ts | 67 +++++++++ generateKlc.ts | 2 +- output/Manoonchai/thaimnc/background.js | 125 +++++++++++++++ output/Manoonchai/thaimnc/icon128.png | Bin 0 -> 8892 bytes output/Manoonchai/thaimnc/icon16.png | Bin 0 -> 109 bytes output/Manoonchai/thaimnc/icon48.png | Bin 0 -> 2337 bytes output/Manoonchai/thaimnc/manifest.json | 27 ++++ 10 files changed, 433 insertions(+), 1 deletion(-) create mode 100644 generateChr_background.ts create mode 100644 generateChr_manifest.ts create mode 100644 output/Manoonchai/thaimnc/background.js create mode 100644 output/Manoonchai/thaimnc/icon128.png create mode 100644 output/Manoonchai/thaimnc/icon16.png create mode 100644 output/Manoonchai/thaimnc/icon48.png create mode 100644 output/Manoonchai/thaimnc/manifest.json diff --git a/README.md b/README.md index 6d39c47..737662c 100644 --- a/README.md +++ b/README.md @@ -10,3 +10,4 @@ Modify, and generate keyboard layout from single JSON file. Built with TypeScrip - `.klc` (Windows) - `.kcm` (Android Physical keyboard) - XKB (Linux) + - remap extension for Chrome OS (Manifest V3) (icons must be added manually / alphanumeric-shortcut keys will not work.) \ No newline at end of file diff --git a/cli.ts b/cli.ts index 6ce0887..3fa2670 100644 --- a/cli.ts +++ b/cli.ts @@ -5,6 +5,8 @@ import { generateKeylayout } from "./generateKeylayout" import { generateKlc } from "./generateKlc" import { generateXkb } from "./generateXkb" import { generateKcm } from "./generateKcm" +import { generateChr_background } from "./generateChr_background" +import { generateChr_manifest } from "./generateChr_manifest" import { fixUnicode } from "./utils" // eslint-disable-next-line @typescript-eslint/no-var-requires @@ -94,4 +96,22 @@ const choices = filenames.map((filename) => ({ console.error(e) process.exit(1) } + + // Chr___OS + try { + const layoutName = response.input.split(".").slice(0, -1).join(".") + const dir = `output/${layoutName}/${jsonInput.os.windows.installerName.toLowerCase()}` + if (!fs.existsSync(dir)){ + fs.mkdirSync(dir); + } + const outputManifest = dir+`/manifest.json` + await generateChr_manifest(jsonInput, outputManifest) + console.log(`Output : ${outputManifest}`) + const outputBackground = dir+`/background.js` + await generateChr_background(jsonInput, outputBackground) + console.log(`Output : ${outputBackground}`) + } catch (e) { + console.error(e) + process.exit(1) + } })() diff --git a/generateChr_background.ts b/generateChr_background.ts new file mode 100644 index 0000000..6e1a125 --- /dev/null +++ b/generateChr_background.ts @@ -0,0 +1,192 @@ +import { + plainToClass +} from "class-transformer" +import { + validate +} from "class-validator" +import fs from "fs" +import { + Layout, + WindowsAttributes +} from "./main" + +export async function generateChr_background( + content: Record < string, unknown > , + outputPath: string, +): Promise < void > { + const layout = plainToClass(Layout, content) + const errors = await validate(layout) + + if (errors.length) { + throw new Error(errors.map((e) => e.toString()).join(", ")) + } + + const windowsErrors = await validate( + plainToClass(WindowsAttributes, layout.os.windows), + ) + + if (windowsErrors.length) { + throw new Error(windowsErrors.map((e) => e.toString()).join(", ")) + } + + function toCheck(str: string) { + // let hex, i + // let result = "" + // for (i = 0; i < str.length; i++) { + // hex = str.charCodeAt(i).toString(16) + // result += "\\u" + ("0000" + hex).slice(-4) + // } + return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); + } + + const klfDefaultLayout = { + "1": "Digit1", + "2": "Digit2", + "3": "Digit3", + "4": "Digit4", + "5": "Digit5", + "6": "Digit6", + "7": "Digit7", + "8": "Digit8", + "9": "Digit9", + "0": "Digit0", + "-": "Minus", + "=": "Equal", + "`": "Backquote", + q: "KeyQ", + w: "KeyW", + e: "KeyE", + r: "KeyR", + t: "KeyT", + y: "KeyY", + u: "KeyU", + i: "KeyI", + o: "KeyO", + p: "KeyP", + "[": "BracketLeft", + "]": "BracketRight", + a: "KeyA", + s: "KeyS", + d: "KeyD", + f: "KeyF", + g: "KeyG", + h: "KeyH", + j: "KeyJ", + k: "KeyK", + l: "KeyL", + ";": "Semicolon", + "'": "Quote", + "\\": "Backslash", + z: "KeyZ", + x: "KeyX", + c: "KeyC", + v: "KeyV", + b: "KeyB", + n: "KeyN", + m: "KeyM", + ",": "Comma", + ".": "Period", + "/": "Slash", + " ": "Space", + KPDL: "NumpadDecimal", + } + + const lines = `/*# License: ${layout.license} +Generated via github.com/Manoonchai/kiimo +*/ +var AltGr = { PLAIN: "plain", ALTERNATE: "alternate" }; +var Shift = { PLAIN: "plain", SHIFTED: "shifted" }; + +var contextID = -1; +var altGrState = AltGr.PLAIN; +var shiftState = Shift.PLAIN; +var lastRemappedKeyEvent = undefined; + +var lut = {` + +const endLines = ` +}; + + +chrome.input.ime.onFocus.addListener(function(context) { + contextID = context.contextID; +}); + +function updateAltGrState(keyData) { + altGrState = (keyData.code == "AltRight") ? ((keyData.type == "keydown") ? AltGr.ALTERNATE : AltGr.PLAIN) + : altGrState; +} + +function updateShiftState(keyData) { + shiftState = ((keyData.shiftKey && !(keyData.capsLock)) || (!(keyData.shiftKey) && keyData.capsLock)) ? + Shift.SHIFTED : Shift.PLAIN; +} + +function isPureModifier(keyData) { + return (keyData.key == "Shift") || (keyData.key == "Ctrl") || (keyData.key == "Alt"); +} + +function isRemappedEvent(keyData) { + // hack, should check for a sender ID (to be added to KeyData) + return lastRemappedKeyEvent != undefined && + (lastRemappedKeyEvent.key == keyData.key && + lastRemappedKeyEvent.code == keyData.code && + lastRemappedKeyEvent.type == keyData.type + ); // requestID would be different so we are not checking for it +} + + +chrome.input.ime.onKeyEvent.addListener( + function(engineID, keyData) { + var handled = false; + + if (isRemappedEvent(keyData)) { + lastRemappedKeyEvent = undefined; + return handled; + } + + updateAltGrState(keyData); + updateShiftState(keyData); + + if (lut[keyData.code]) { + //avoid hell key:process loop + if (keyData.ctrlKey === true && keyData.code != "Space") { + return; + } + var remappedKeyData = keyData; + remappedKeyData.key = lut[keyData.code][altGrState][shiftState]; + remappedKeyData.code = lut[keyData.code].code; + + if (chrome.input.ime.sendKeyEvents != undefined) { + chrome.input.ime.sendKeyEvents({"contextID": contextID, "keyData": [remappedKeyData]}); + handled = true; + lastRemappedKeyEvent = remappedKeyData; + } else if (keyData.type == "keydown" && !isPureModifier(keyData)) { + chrome.input.ime.commitText({"contextID": contextID, "text": remappedKeyData.key}); + handled = true; + } + } + + return handled; +}); +` + + const layoutLines = [""] + Object.entries(klfDefaultLayout).forEach(([key, value]) => { + const extensions = + `: { "plain": {"plain": "${toCheck(layout.keys[key][0])}"` + + `, "shifted": "${toCheck(layout.keys[key][1])}"}` + + `, "alternate": {"plain": "${toCheck(layout.keys[key][3])}"` + + `, "shifted":"${toCheck(layout.keys[key][5])}"}, ` + + `"code": "${value}"},` + + layoutLines.push([`"${value}"`, ...extensions].join("")) + }) + + fs.writeFileSync( + outputPath, + [lines, layoutLines.join("\n"),endLines].join(""), { + encoding: "utf8", + }, + ) +} \ No newline at end of file diff --git a/generateChr_manifest.ts b/generateChr_manifest.ts new file mode 100644 index 0000000..499a6d3 --- /dev/null +++ b/generateChr_manifest.ts @@ -0,0 +1,67 @@ +import { plainToClass } from "class-transformer" +import { validate } from "class-validator" +import fs from "fs" +import { Layout, WindowsAttributes } from "./main" + +export async function generateChr_manifest( + content: Record, + outputPath: string, +): Promise { + const layout = plainToClass(Layout, content) + const errors = await validate(layout) + + if (errors.length) { + throw new Error(errors.map((e) => e.toString()).join(", ")) + } + + const windowsErrors = await validate( + plainToClass(WindowsAttributes, layout.os.windows), + ) + + if (windowsErrors.length) { + throw new Error(windowsErrors.map((e) => e.toString()).join(", ")) + } + + const chrLocales = { + Thai: "th", + Laos: "la", + } + + const lines = +`{ + "name": "${layout.language} ${layout.name} v${layout.version}", + "version": "${layout.version}", + "manifest_version": 3, + "description": "${layout.language} ${layout.name} v${layout.version}", + "background": { + "scripts": ["background.js"] + }, + "icons": { + "16": "icon16.png", + "48": "icon48.png", + "128": "icon128.png" + }, + "permissions": [ + "input" + ], + "input_components": [ + { + "name": "${layout.language} ${layout.name} v${layout.version}", + "type": "ime", + "id": "${chrLocales[layout.language as keyof typeof chrLocales]}_${layout.name.toLowerCase()}_remap", + "description": "${layout.language} ${layout.name} v${layout.version}", + "language": "${chrLocales[layout.language as keyof typeof chrLocales]}", + "layouts": ["la(stea)"] + } + ] +}` +//"layouts": ["la(stea)"] due all embed-thai-layout lack of "level3(ralt_switch)", use laos instead. + + fs.writeFileSync( + outputPath, + lines, + { + encoding: "utf8", + }, + ) +} diff --git a/generateKlc.ts b/generateKlc.ts index e7e8863..795cbe6 100644 --- a/generateKlc.ts +++ b/generateKlc.ts @@ -24,7 +24,7 @@ export async function generateKlc( const klcLocales = { Thai: "th-TH", - Lao: "lo-LA", + Laos: "lo-LA", } function toHex(str: string) { diff --git a/output/Manoonchai/thaimnc/background.js b/output/Manoonchai/thaimnc/background.js new file mode 100644 index 0000000..8464fd0 --- /dev/null +++ b/output/Manoonchai/thaimnc/background.js @@ -0,0 +1,125 @@ +/*# License: MIT +Generated via github.com/Manoonchai/kiimo +*/ +var AltGr = { PLAIN: "plain", ALTERNATE: "alternate" }; +var Shift = { PLAIN: "plain", SHIFTED: "shifted" }; + +var contextID = -1; +var altGrState = AltGr.PLAIN; +var shiftState = Shift.PLAIN; +var lastRemappedKeyEvent = undefined; + +var lut = { +"Digit0": { "plain": {"plain": "0", "shifted": ")"}, "alternate": {"plain": "๐", "shifted":""}, "code": "Digit0"}, +"Digit1": { "plain": {"plain": "1", "shifted": "!"}, "alternate": {"plain": "๑", "shifted":""}, "code": "Digit1"}, +"Digit2": { "plain": {"plain": "2", "shifted": "@"}, "alternate": {"plain": "๒", "shifted":""}, "code": "Digit2"}, +"Digit3": { "plain": {"plain": "3", "shifted": "#"}, "alternate": {"plain": "๓", "shifted":""}, "code": "Digit3"}, +"Digit4": { "plain": {"plain": "4", "shifted": "$"}, "alternate": {"plain": "๔", "shifted":""}, "code": "Digit4"}, +"Digit5": { "plain": {"plain": "5", "shifted": "%"}, "alternate": {"plain": "๕", "shifted":""}, "code": "Digit5"}, +"Digit6": { "plain": {"plain": "6", "shifted": "^"}, "alternate": {"plain": "๖", "shifted":""}, "code": "Digit6"}, +"Digit7": { "plain": {"plain": "7", "shifted": "&"}, "alternate": {"plain": "๗", "shifted":""}, "code": "Digit7"}, +"Digit8": { "plain": {"plain": "8", "shifted": "*"}, "alternate": {"plain": "๘", "shifted":""}, "code": "Digit8"}, +"Digit9": { "plain": {"plain": "9", "shifted": "("}, "alternate": {"plain": "๙", "shifted":""}, "code": "Digit9"}, +"Minus": { "plain": {"plain": "-", "shifted": "_"}, "alternate": {"plain": "÷", "shifted":""}, "code": "Minus"}, +"Equal": { "plain": {"plain": "=", "shifted": "+"}, "alternate": {"plain": "×", "shifted":""}, "code": "Equal"}, +"Backquote": { "plain": {"plain": "`", "shifted": "~"}, "alternate": {"plain": "`", "shifted":""}, "code": "Backquote"}, +"KeyQ": { "plain": {"plain": "ใ", "shifted": "ฒ"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyQ"}, +"KeyW": { "plain": {"plain": "ต", "shifted": "ฏ"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyW"}, +"KeyE": { "plain": {"plain": "ห", "shifted": "ซ"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyE"}, +"KeyR": { "plain": {"plain": "ล", "shifted": "ญ"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyR"}, +"KeyT": { "plain": {"plain": "ส", "shifted": "ฟ"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyT"}, +"KeyY": { "plain": {"plain": "ป", "shifted": "ฉ"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyY"}, +"KeyU": { "plain": {"plain": "ั", "shifted": "ึ"}, "alternate": {"plain": "ฺ", "shifted":""}, "code": "KeyU"}, +"KeyI": { "plain": {"plain": "ก", "shifted": "ธ"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyI"}, +"KeyO": { "plain": {"plain": "ิ", "shifted": "ฐ"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyO"}, +"KeyP": { "plain": {"plain": "บ", "shifted": "ฎ"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyP"}, +"BracketLeft": { "plain": {"plain": "็", "shifted": "ฆ"}, "alternate": {"plain": "[", "shifted":"{"}, "code": "BracketLeft"}, +"BracketRight": { "plain": {"plain": "ฬ", "shifted": "ฑ"}, "alternate": {"plain": "]", "shifted":"}"}, "code": "BracketRight"}, +"KeyA": { "plain": {"plain": "ง", "shifted": "ษ"}, "alternate": {"plain": "◌", "shifted":""}, "code": "KeyA"}, +"KeyS": { "plain": {"plain": "เ", "shifted": "ถ"}, "alternate": {"plain": "๏", "shifted":""}, "code": "KeyS"}, +"KeyD": { "plain": {"plain": "ร", "shifted": "แ"}, "alternate": {"plain": "๛", "shifted":""}, "code": "KeyD"}, +"KeyF": { "plain": {"plain": "น", "shifted": "ช"}, "alternate": {"plain": "฿", "shifted":""}, "code": "KeyF"}, +"KeyG": { "plain": {"plain": "ม", "shifted": "พ"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyG"}, +"KeyH": { "plain": {"plain": "อ", "shifted": "ผ"}, "alternate": {"plain": "ํ", "shifted":""}, "code": "KeyH"}, +"KeyJ": { "plain": {"plain": "า", "shifted": "ำ"}, "alternate": {"plain": "ๅ", "shifted":""}, "code": "KeyJ"}, +"KeyK": { "plain": {"plain": "่", "shifted": "ข"}, "alternate": {"plain": "ฃ", "shifted":""}, "code": "KeyK"}, +"KeyL": { "plain": {"plain": "้", "shifted": "โ"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyL"}, +"Semicolon": { "plain": {"plain": "ว", "shifted": "ภ"}, "alternate": {"plain": ";", "shifted":":"}, "code": "Semicolon"}, +"Quote": { "plain": {"plain": "ื", "shifted": "\""}, "alternate": {"plain": "'", "shifted":"\""}, "code": "Quote"}, +"Backslash": { "plain": {"plain": "ฯ", "shifted": "ฌ"}, "alternate": {"plain": "\\", "shifted":"|"}, "code": "Backslash"}, +"KeyZ": { "plain": {"plain": "ุ", "shifted": "ฤ"}, "alternate": {"plain": "ฦ", "shifted":""}, "code": "KeyZ"}, +"KeyX": { "plain": {"plain": "ไ", "shifted": "ฝ"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyX"}, +"KeyC": { "plain": {"plain": "ท", "shifted": "ๆ"}, "alternate": {"plain": "๚", "shifted":""}, "code": "KeyC"}, +"KeyV": { "plain": {"plain": "ย", "shifted": "ณ"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyV"}, +"KeyB": { "plain": {"plain": "จ", "shifted": "๊"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyB"}, +"KeyN": { "plain": {"plain": "ค", "shifted": "๋"}, "alternate": {"plain": "ฅ", "shifted":""}, "code": "KeyN"}, +"KeyM": { "plain": {"plain": "ี", "shifted": "์"}, "alternate": {"plain": "๎", "shifted":""}, "code": "KeyM"}, +"Comma": { "plain": {"plain": "ด", "shifted": "ศ"}, "alternate": {"plain": ",", "shifted":"<"}, "code": "Comma"}, +"Period": { "plain": {"plain": "ะ", "shifted": "ฮ"}, "alternate": {"plain": ".", "shifted":">"}, "code": "Period"}, +"Slash": { "plain": {"plain": "ู", "shifted": "?"}, "alternate": {"plain": "/", "shifted":"?"}, "code": "Slash"}, +"Space": { "plain": {"plain": " ", "shifted": " "}, "alternate": {"plain": " ", "shifted":" "}, "code": "Space"}, +"NumpadDecimal": { "plain": {"plain": ".", "shifted": ","}, "alternate": {"plain": ".", "shifted":"."}, "code": "NumpadDecimal"}, +}; + + +chrome.input.ime.onFocus.addListener(function(context) { + contextID = context.contextID; +}); + +function updateAltGrState(keyData) { + altGrState = (keyData.code == "AltRight") ? ((keyData.type == "keydown") ? AltGr.ALTERNATE : AltGr.PLAIN) + : altGrState; +} + +function updateShiftState(keyData) { + shiftState = ((keyData.shiftKey && !(keyData.capsLock)) || (!(keyData.shiftKey) && keyData.capsLock)) ? + Shift.SHIFTED : Shift.PLAIN; +} + +function isPureModifier(keyData) { + return (keyData.key == "Shift") || (keyData.key == "Ctrl") || (keyData.key == "Alt"); +} + +function isRemappedEvent(keyData) { + // hack, should check for a sender ID (to be added to KeyData) + return lastRemappedKeyEvent != undefined && + (lastRemappedKeyEvent.key == keyData.key && + lastRemappedKeyEvent.code == keyData.code && + lastRemappedKeyEvent.type == keyData.type + ); // requestID would be different so we are not checking for it +} + + +chrome.input.ime.onKeyEvent.addListener( + function(engineID, keyData) { + var handled = false; + + if (isRemappedEvent(keyData)) { + lastRemappedKeyEvent = undefined; + return handled; + } + + updateAltGrState(keyData); + updateShiftState(keyData); + + if (lut[keyData.code]) { + //avoid hell key:process loop + if (keyData.ctrlKey === true && keyData.code != "Space") { + return; + } + var remappedKeyData = keyData; + remappedKeyData.key = lut[keyData.code][altGrState][shiftState]; + remappedKeyData.code = lut[keyData.code].code; + + if (chrome.input.ime.sendKeyEvents != undefined) { + chrome.input.ime.sendKeyEvents({"contextID": contextID, "keyData": [remappedKeyData]}); + handled = true; + lastRemappedKeyEvent = remappedKeyData; + } else if (keyData.type == "keydown" && !isPureModifier(keyData)) { + chrome.input.ime.commitText({"contextID": contextID, "text": remappedKeyData.key}); + handled = true; + } + } + + return handled; +}); diff --git a/output/Manoonchai/thaimnc/icon128.png b/output/Manoonchai/thaimnc/icon128.png new file mode 100644 index 0000000000000000000000000000000000000000..5f1bb3b3d5376f967ee0b956336e5f8d13d086f4 GIT binary patch literal 8892 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 Ke3h(e(EkCoQq7V8 literal 0 HcmV?d00001 diff --git a/output/Manoonchai/thaimnc/icon16.png b/output/Manoonchai/thaimnc/icon16.png new file mode 100644 index 0000000000000000000000000000000000000000..ea370f9d18ff3a02f217cd116629b23fd547bf4d GIT binary patch literal 109 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;TYyi9E0F&G|NqjP^X~##N}eu` zAsp9}6A}_OOh_yUY*3PBWfN0L`QLufm9wkil!OFBX*a9h$#<3ufT|fhUHx3vIVCg! E09WB1;Q#;t literal 0 HcmV?d00001 diff --git a/output/Manoonchai/thaimnc/icon48.png b/output/Manoonchai/thaimnc/icon48.png new file mode 100644 index 0000000000000000000000000000000000000000..dfaa0b086e01a0b9442531ff40858dff2e8de2a2 GIT binary patch literal 2337 zcmV++3EuXJP)(urYiuKjVnZ-z9~fL;2{BHp z9%&xznQ!KQX3qTQ%sHd6F)08_ff`_kDmK6jYzB%{yG7s@5ClenE5Lt%>%c4!%N2l@ z<9EeCE#Ls!fd-&l0oL#E?XprR2#f%IfD@PmBHUv!0xiJ50Jj=YHdrF6uTIss@m>Je z04s1DxCSic0eEV;t@=K$#?tZyz7Y5`a2}Yy2f$OyJn(}Wvv8x}OMnhFGt2h@{AyWN zV|FMEImrXS8-Vvd0#7Yoh2eo*X8sLeW<3LGnzmuEYxFUru#{xu@k}=VSKuV@r_@TD z%|=^W8!as@*lae6i;MC3e2Bh3N)xL9I+iu`0Gn+OUuoBtW3JPx+EA3%B4$}tY&Ye3a)6>&( z{P=O%ym@odi~{oFi!aK=#DuurZfS3CPx?Nw?STUa#O-#=`1rVVbadpp;oS=B%3ezF zZH_4aCdpnK8XBmtuV-p%3a8V_ufP5puLICDjsE_AhFn8DYfdZZDs8q_VSJlmlYi^cf*>#u2QYGUu+y}bMG zyBs`tkm>2^_=zea*lf1D27kAwcZ!q)J69DbTC3&o@Gu{I@BuS3GdLU$_U_$_uIov5 zTc8(!wl=6duTBxL-JtHUce(~LG&IE6*ceWylg7qIN=izS6liX4=E=W2xuyaeobfbw z3TQB7GoMTn3WezF>!Yu)FRiY#vop>z_fg9ATzu_JW|3-A_i2M~*6(Eh8Qx2?2AG|lO^1(-}G78VwW#gfCJ zu~>{?Fi3xYKc`Qh#^rJ)DUm^eW#Hci6=+?|=F9=?*s+6S$ByyTQ%?~Jg>X8Z1OkB- z4|H{Qx7paeXE*20onvZhD&yc*tCgppewx9-K}JSKR#p!|*L5rw3%hph;_%_aSS%La zd+$B2T)DE=K3N2YQLeTgZc&~+VM*9iuLeDcXB^z`(wu&}_h z&pt~_OG{Q_P$8D1;)T_qQs!2dFaDvU-91qQ<5Fn+&3t4(TX#A30ml$mV>68~Gh zZiYf3bX}*gFl%i025=ULty0M((67Sg$wWIh$HL+Qm6es$)zzf|(=-jU*^K333(L#P z@k@UunV+9$X=w?w*^Jq2j?-+S(sgxpR8&+DiA0#2o6FSAQbIx`PMs0pG%%GK{&TzC zjE|3FwOVmF92kwpG&68G9JIE!GCMoV)vH&tDljrKLMRks*REYS9F8QD5)n)$6Z`h< zqpq%w@$vB$rb=J&Nrg3%8XFC&IOG$nad{CT5C~9KRz_P}8_mtl6c-m0iA0D-qtw*Y z@ci@7^XjXwQdL#OS6_WaPfrigXf&g__Fw>6*4EaHRGdhKt*x!{#TQ>lAP^9b$0LJ-gYxY+-^!&+m&E7uiP!6u zk3RZHs;a8i6_duC8XwmMxe}CPqg`>F(~PySp2Y$CKLC81N6^ zzjw+~76ONWf2KyL0U8<_*tTsOn>KA?adDB!$w`KXhY^u=dzY)5wxy+o+S*zQ3k#W> zn`3lzl+n@AOrJ~x$ADgyOUr+P<8I4cBspe)*Kiq$W_y@CJ-7Kk`@2(36SYw900000NkvXX Hu0mjff2);g literal 0 HcmV?d00001 diff --git a/output/Manoonchai/thaimnc/manifest.json b/output/Manoonchai/thaimnc/manifest.json new file mode 100644 index 0000000..561c44c --- /dev/null +++ b/output/Manoonchai/thaimnc/manifest.json @@ -0,0 +1,27 @@ +{ + "name": "Thai Manoonchai v1.0", + "version": "1.0", + "manifest_version": 3, + "description": "Thai Manoonchai v1.0", + "background": { + "scripts": ["background.js"] + }, + "icons": { + "16": "icon16.png", + "48": "icon48.png", + "128": "icon128.png" + }, + "permissions": [ + "input" + ], + "input_components": [ + { + "name": "Thai Manoonchai v1.0", + "type": "ime", + "id": "th_manoonchai_remap", + "description": "Thai Manoonchai v1.0", + "language": "th", + "layouts": ["la(stea)"] + } + ] +} \ No newline at end of file From 17e40517004635120f0ee34effc8cc385c1347db Mon Sep 17 00:00:00 2001 From: Saamkhaih Kyakya <70475761+hiohlan@users.noreply.github.com> Date: Thu, 28 Dec 2023 02:16:17 +0700 Subject: [PATCH 2/4] fix: genChr background.script -> background.service_worker --- generateChr_manifest.ts | 2 +- output/Manoonchai/thaimnc/manifest.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/generateChr_manifest.ts b/generateChr_manifest.ts index 499a6d3..ed789d5 100644 --- a/generateChr_manifest.ts +++ b/generateChr_manifest.ts @@ -34,7 +34,7 @@ export async function generateChr_manifest( "manifest_version": 3, "description": "${layout.language} ${layout.name} v${layout.version}", "background": { - "scripts": ["background.js"] + "service_worker": ["background.js"] }, "icons": { "16": "icon16.png", diff --git a/output/Manoonchai/thaimnc/manifest.json b/output/Manoonchai/thaimnc/manifest.json index 561c44c..939faed 100644 --- a/output/Manoonchai/thaimnc/manifest.json +++ b/output/Manoonchai/thaimnc/manifest.json @@ -4,7 +4,7 @@ "manifest_version": 3, "description": "Thai Manoonchai v1.0", "background": { - "scripts": ["background.js"] + "service_worker": ["background.js"] }, "icons": { "16": "icon16.png", From aec03fc46c44704afdba76e6b1b9c7042f14c85b Mon Sep 17 00:00:00 2001 From: Saamkhaih Kyakya <70475761+hiohlan@users.noreply.github.com> Date: Thu, 28 Dec 2023 02:22:50 +0700 Subject: [PATCH 3/4] fix: genChr remove [] from service_worker --- generateChr_manifest.ts | 2 +- output/Manoonchai/thaimnc/manifest.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/generateChr_manifest.ts b/generateChr_manifest.ts index ed789d5..32e37b2 100644 --- a/generateChr_manifest.ts +++ b/generateChr_manifest.ts @@ -34,7 +34,7 @@ export async function generateChr_manifest( "manifest_version": 3, "description": "${layout.language} ${layout.name} v${layout.version}", "background": { - "service_worker": ["background.js"] + "service_worker": "background.js" }, "icons": { "16": "icon16.png", diff --git a/output/Manoonchai/thaimnc/manifest.json b/output/Manoonchai/thaimnc/manifest.json index 939faed..c8925b6 100644 --- a/output/Manoonchai/thaimnc/manifest.json +++ b/output/Manoonchai/thaimnc/manifest.json @@ -4,7 +4,7 @@ "manifest_version": 3, "description": "Thai Manoonchai v1.0", "background": { - "service_worker": ["background.js"] + "service_worker": "background.js" }, "icons": { "16": "icon16.png", From 55c099182319bc9efffa4efb1258816c4dc189c8 Mon Sep 17 00:00:00 2001 From: Saamkhaih Kyakya <70475761+hiohlan@users.noreply.github.com> Date: Thu, 28 Dec 2023 21:35:19 +0700 Subject: [PATCH 4/4] fix: typo Laos -> Lao --- generateChr_manifest.ts | 2 +- generateKlc.ts | 2 +- input/{Manoonchai_Laos.json => Manoonchai_Lao.json} | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) rename input/{Manoonchai_Laos.json => Manoonchai_Lao.json} (96%) diff --git a/generateChr_manifest.ts b/generateChr_manifest.ts index 32e37b2..4291928 100644 --- a/generateChr_manifest.ts +++ b/generateChr_manifest.ts @@ -24,7 +24,7 @@ export async function generateChr_manifest( const chrLocales = { Thai: "th", - Laos: "la", + Lao: "la", } const lines = diff --git a/generateKlc.ts b/generateKlc.ts index 795cbe6..e7e8863 100644 --- a/generateKlc.ts +++ b/generateKlc.ts @@ -24,7 +24,7 @@ export async function generateKlc( const klcLocales = { Thai: "th-TH", - Laos: "lo-LA", + Lao: "lo-LA", } function toHex(str: string) { diff --git a/input/Manoonchai_Laos.json b/input/Manoonchai_Lao.json similarity index 96% rename from input/Manoonchai_Laos.json rename to input/Manoonchai_Lao.json index 834342b..06e5771 100644 --- a/input/Manoonchai_Laos.json +++ b/input/Manoonchai_Lao.json @@ -1,12 +1,12 @@ { - "name": "Manoonchai Laos Pali", + "name": "Manoonchai Lao-Pali", "version": "1.0", - "language": "Laos", + "language": "Lao", "layers": ["Base", "Shift", "Command", "AltGr", "Control", "ShiftAltGr"], "license": "MIT", "os": { "windows": { - "installerName": "LaosMnc", + "installerName": "LaoMnc", "company": "Manoonchai", "localeId": "00000454" }