Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chromebook Crashes and Reboots when Trying to use Custom Keyboard Layout #100

Open
ghost opened this issue Feb 13, 2021 · 2 comments
Open

Comments

@ghost
Copy link

ghost commented Feb 13, 2021

I made a custom keyboard layout using the Esperanto preset as a boilerplate. I was also able to set it as an input method. But, when I went to use it, my Chromebook crashed and rebooted.

My Filesystem Looks like this:

*Layout Name
* layoutremap
* manifest.json (manifest1)
* background.js
* layoutxkb
* manifest.json (manifest2)
* Reference
* ReferenceImage.png

Manifest 1:
`/*
Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
{
"name": "name",
"version": "1.0",
"manifest_version": 2,
"description": "desc",
"background": {
"scripts": ["background.js"]
},
"permissions": [
"input"
],
"input_components": [
{
"name": "name",
"type": "ime",
"id": "id",
"description": "desc", // user visible description
"language": "en", // The primary language this IME is used for
"layouts": ["en"]
}
]
}`

background.js:
`/*
Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
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 = {
"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"},
"Digit0": { "plain": {"plain": "0", "shifted": ")"}, "alternate": {"plain": "", "shifted":""}, "code": "Digit0"},
"Minus": { "plain": {"plain": "-", "shifted": "_"}, "alternate": {"plain": "", "shifted":""}, "code": "Minus"},
"Equal": { "plain": {"plain": "=", "shifted": "+"}, "alternate": {"plain": "", "shifted":""}, "code": "Equal"},
"KeyQ": { "plain": {"plain": "z", "shifted": "Z"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyQ"},
"KeyW": { "plain": {"plain": "n", "shifted": "N"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyW"},
"KeyE": { "plain": {"plain": "o", "shifted": "O"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyE"},
"KeyR": { "plain": {"plain": "l", "shifted": "L"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyR"},
"KeyT": { "plain": {"plain": "m", "shifted": "M"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyT"},
"KeyY": { "plain": {"plain": "u", "shifted": "U"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyY"},
"KeyU": { "plain": {"plain": "h", "shifted": "H"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyU"},
"KeyI": { "plain": {"plain": "a", "shifted": "A"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyI"},
"KeyO": { "plain": {"plain": "i", "shifted": "I"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyO"},
"KeyP": { "plain": {"plain": "q", "shifted": "Q"}, "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": "r", "shifted": "R"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyA"},
"KeyS": { "plain": {"plain": "p", "shifted": "P"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyS"},
"KeyD": { "plain": {"plain": "c", "shifted": "C"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyD"},
"KeyF": { "plain": {"plain": "t", "shifted": "T"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyF"},
"KeyG": { "plain": {"plain": "w", "shifted": "W"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyG"},
"KeyH": { "plain": {"plain": "g", "shifted": "G"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyH"},
"KeyJ": { "plain": {"plain": "e", "shifted": "E"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyJ"},
"KeyK": { "plain": {"plain": "d", "shifted": "D"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyK"},
"KeyL": { "plain": {"plain": "f", "shifted": "F"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyL"},
"Semicolon": { "plain": {"plain": "s", "shifted": "S"}, "alternate": {"plain": "", "shifted":""}, "code": "Semicolon"},
"Quote": { "plain": {"plain": "?", "shifted": "!"}, "alternate": {"plain": "", "shifted":""}, "code": "Quote"},
"KeyZ": { "plain": {"plain": "'", "shifted": """}, "alternate": {"plain": "", "shifted":""}, "code": "KeyZ"},
"KeyX": { "plain": {"plain": "j", "shifted": "J"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyX"},
"KeyC": { "plain": {"plain": "k", "shifted": "K"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyC"},
"KeyV": { "plain": {"plain": "b", "shifted": "B"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyV"},
"KeyB": { "plain": {"plain": ".", "shifted": ","}, "alternate": {"plain": "", "shifted":""}, "code": "KeyB"},
"KeyN": { "plain": {"plain": "y", "shifted": "Y"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyN"},
"KeyM": { "plain": {"plain": "v", "shifted": "V"}, "alternate": {"plain": "", "shifted":""}, "code": "KeyM"},
"Comma": { "plain": {"plain": "x", "shifted": "X"}, "alternate": {"plain": "", "shifted":""}, "code": "Comma"},
"Period": { "plain": {"plain": ";", "shifted": ":"}, "alternate": {"plain": "", "shifted":""}, "code": "Period"},
"Slash": { "plain": {"plain": "/", "shifted": "\"}, "alternate": {"plain": "", "shifted":""}, "code": "Slash"},
};

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]) {
      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;

});`

Manifest 2:
`/* Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
{
"name": "name",
"version": "1.0",
"manifest_version": 2,
"description": "desc",
"permissions": [
"input"
],
"input_components": [
{
"name": "name",
"type": "ime",
"id": "name_xkb",
"description": "desc", // user visible description
"language": "en-US", // The primary language this IME is used for
"layouts": ["us"]
}
]
}`

@bderrly
Copy link
Contributor

bderrly commented Apr 13, 2021

The manifest.json language and layouts options are invalid. For Esperanto I think the language needs to be either "eo" or "epo" (I'm not sure which will work). The layout should be "basic" once the language is selected. You can look at the different layout options for Esperanto in the xkeyboard-config repository.

"language": "epo",
"layouts": ["basic"]

@hickford
Copy link
Contributor

Ideally Chrome OS would handle the error gracefully rather than crash. I reported bug https://crbug.com/1199072 "Keyboard layout extension referencing non-existent xkb layout crashes Chrome OS"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants