├── .gitignore
├── Makefile
├── README.md
├── chrome.manifest
├── components
└── keyconfig-service.js
├── content
├── defaultPreferencesLoader.jsm
├── edit.xul
├── keyconfig.js
├── keyconfig.xul
├── menumanipulator.js
└── overlay.xul
├── defaults
└── preferences
│ └── keyconfig.js
├── functions_for_keyconfig-1.3.7-fx.xpi
├── icon.png
├── icon64.png
├── install.rdf
├── locale
├── cs-CZ
│ └── keyconfig.ent
├── da-DK
│ └── keyconfig.ent
├── de-DE
│ └── keyconfig.ent
├── en-US
│ └── keyconfig.ent
├── es-AR
│ └── keyconfig.ent
├── fr-FR
│ └── keyconfig.ent
├── it-IT
│ └── keyconfig.ent
├── ja-JP
│ └── keyconfig.ent
├── ko-KR
│ └── keyconfig.ent
├── ru-RU
│ └── keyconfig.ent
├── sk-SK
│ └── keyconfig.ent
├── zh-CN
│ └── keyconfig.ent
└── zh-TW
│ └── keyconfig.ent
└── skin
└── keyconfig.css
/.gitignore:
--------------------------------------------------------------------------------
1 | keyconfig.xpi
2 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | ZIPFILES=install.rdf chrome.manifest README.md icon.png icon64.png defaults \
2 | components content locale skin
3 | DEPFILES=$(shell find $(ZIPFILES) -type f -print)
4 |
5 | keyconfig.xpi: $(DEPFILES)
6 | rm -f $@.tmp
7 | zip -r $@.tmp $(ZIPFILES)
8 | mv -f $@.tmp $@
9 |
10 | clean: ; -rm -rf keyconfig.xpi
11 |
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # dorando-keyconfig
2 |
3 | A modified version of [Dorando](http://mozilla.dorando.at/readme.html)'s tool to rebind keys in Mozilla apps. It is designed to be a drop-in replacement, and will keep your old settings. (See official version webpage for upgrade instructions.)
4 |
5 | The only changes here are non-functional changes for compatibility with newer app versions, since Dorando is no longer maintaining the add-on.
6 |
7 | Note that this add-on is _not_ compatible with Firefox 57 and newer, since it uses old add-on APIs that are no longer supported as of Firefox 57. However, it remains compatible with current versions of Thunderbird and SeaMonkey.
8 |
9 | You can install this add-on from [addons.thunderbird.net](https://addons.thunderbird.net/thunderbird/addon/dorando-keyconfig) and [addons.palemoon.org](https://addons.palemoon.org/addon/keyconfig/). **If you are replacing Dorando's version of the add-on from 2011 or earlier with this version, make sure to uninstall Dorando's version before installing this one.**
10 |
11 | ## Working with the source code
12 |
13 | To deploy the source code directly into Firefox, Thunderbird, or Mozilla, so that you can make changes here and then test them in the application without having to create and install a new XPI file:
14 |
15 | 1. Install the add-on normally from addons.mozilla.org.
16 |
17 | 2. Shut down the app.
18 |
19 | 3. Locate the "extensions" subdirectory of your app profile directory.
20 |
21 | 4. Locate the file "keyconfig@mozilla.dorando.at.xpi" in that directory and delete it.
22 |
23 | 5. Create a new text file called "keyconfig@mozilla.dorando.at" (note: no ".xpi" extension). In that file, put the full path to the directory this source code is in.
24 |
25 | 6. Locate the "prefs.js" file in your app profile directory.
26 |
27 | 7. Put this in it:
28 |
29 | user_pref("extensions.startupScanScopes", 5);
30 |
31 | 8. Restart the app from the command line with the argument `-purgecaches`.
32 |
33 | 9. Confirm that the add-on shows up in the add-ons listing.
34 |
35 | Whenever you start the app with `-purgecaches` from this point forward, it will reload the current version of the add-on code from your source directory. It may also pick up your changes even when you don't specify `-purgecaches`, but the only way to be _certain_ that it will notice your changes is to specify that argument.
36 |
37 | ## Copyright
38 |
39 | Dorando's original copyright is as follows:
40 |
41 | >Copyright (c) 2004-2011 Dorando.
42 | >Permission is granted to copy, distribute, and/or modify any part of this package.
43 |
44 | The maintainers of this updated version of the add-on do not claim any additional copyright. In other words, the copyright above still applies.
45 |
--------------------------------------------------------------------------------
/chrome.manifest:
--------------------------------------------------------------------------------
1 | content keyconfig content/
2 | content keyconfig-defaults defaults/
3 | locale keyconfig en-US locale/en-US/
4 | locale keyconfig cs-CZ locale/cs-CZ/
5 | locale keyconfig da-DK locale/da-DK/
6 | locale keyconfig de-DE locale/de-DE/
7 | locale keyconfig es-AR locale/es-AR/
8 | locale keyconfig fr-FR locale/fr-FR/
9 | locale keyconfig it-IT locale/it-IT/
10 | locale keyconfig ja-JP locale/ja-JP/
11 | locale keyconfig ko-KR locale/ko-KR/
12 | locale keyconfig ru-RU locale/ru-RU/
13 | locale keyconfig sk-SK locale/sk-SK/
14 | locale keyconfig zh-CN locale/zh-CN/
15 | locale keyconfig zh-TW locale/zh-TW/
16 | skin keyconfig classic/1.0 skin/
17 |
18 | overlay chrome://browser/content/browser.xul chrome://keyconfig/content/overlay.xul
19 | overlay chrome://messenger/content/mailWindowOverlay.xul chrome://keyconfig/content/overlay.xul
20 | overlay chrome://messenger/content/messengercompose/messengercompose.xul chrome://keyconfig/content/overlay.xul
21 | overlay chrome://communicator/content/tasksOverlay.xul chrome://keyconfig/content/overlay.xul
22 | style chrome://keyconfig/content/keyconfig.xul chrome://keyconfig/skin/keyconfig.css
23 |
24 | component {e9f7950e-d78d-4aaa-900a-c43588052eba} components/keyconfig-service.js
25 | contract @dorando.at/keyconfig;1 {e9f7950e-d78d-4aaa-900a-c43588052eba}
26 | category profile-after-change keyconfigService @dorando.at/keyconfig;1
27 |
--------------------------------------------------------------------------------
/components/keyconfig-service.js:
--------------------------------------------------------------------------------
1 | Components.utils.import("chrome://keyconfig/content/defaultPreferencesLoader.jsm");
2 |
3 | function NSGetModule(compMgr, fileSpec) { return Module; }
4 | function NSGetFactory() { return Factory; }
5 |
6 | var Module = {
7 | CID: Components.ID("{e9f7950e-d78d-4aaa-900a-c43588052eba}"),
8 | contractID: "@dorando.at/keyconfig;1",
9 | className: "keyconfigService",
10 |
11 | registerSelf: function (aComponentManager, aFileSpec, aLocation, aType) {
12 | aComponentManager = aComponentManager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
13 |
14 | aComponentManager.registerFactoryLocation(this.CID, this.className, this.contractID, aFileSpec, aLocation, aType);
15 |
16 | var CategoryManager = Components.classes["@mozilla.org/categorymanager;1"]
17 | .getService(Components.interfaces.nsICategoryManager);
18 | CategoryManager.addCategoryEntry("app-startup", this.className, "service," + this.contractID, true, true, null);
19 | },
20 |
21 | getClassObject: function (aComponentManager, aCID, aIID) {
22 | if (!aIID.equals(Components.interfaces.nsIFactory)) throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
23 |
24 | if (aCID.equals(this.CID)) return Factory;
25 |
26 | throw Components.results.NS_ERROR_NO_INTERFACE;
27 | },
28 |
29 | canUnload: function () { return true; }
30 | };
31 |
32 | var Factory = {
33 | createInstance: function (aOuter, aIID)
34 | {
35 | if (aOuter != null) throw Components.results.NS_ERROR_NO_AGGREGATION;
36 |
37 | return new keyconfigService();
38 | }
39 | };
40 |
41 | function keyconfigService() {
42 | this.os.addObserver(this,"domwindowopened",false);
43 | }
44 |
45 | keyconfigService.prototype = {
46 | js: Components.classes["@mozilla.org/moz/jssubscript-loader;1"].getService(Components.interfaces.mozIJSSubScriptLoader),
47 | os: Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService),
48 | ps: Components.classes['@mozilla.org/preferences-service;1']
49 | .getService(Components.interfaces.nsIPrefService).getBranch(""),
50 |
51 | observe: function (aSubject, aTopic, aData) {
52 | if(aTopic == "domwindowopened") {
53 | aSubject.keyconfig = {service: this};
54 | aSubject.addEventListener("load",this.load,true);
55 | }
56 | },
57 |
58 | load: function(event) {
59 | this.removeEventListener(event.type,this.keyconfig.service.load,true);
60 |
61 | this.addEventListener(event.eventPhase == 2 ? "pageshow" : "load",this.keyconfig.service.init,false);
62 | },
63 |
64 | init: function(event) {
65 | // Current Thunderbird nightly builds do not load default preferences
66 | // from overlay add-ons. They're probably going to fix this, but it may go
67 | // away again at some point in the future, and in any case we'll need to do
68 | // it ourselves when we convert from overlay to bootstrapped, and there
69 | // shouldn't be any harm in setting the default values of preferences twice
70 | // (i.e., both Thunderbird and our code doing it).
71 | // This is in a try/catch because if it fails it's probably because
72 | // setStringPref failed, in which case we're running inside an earlier
73 | // application version which has already loaded the default preferences
74 | // automatically.
75 | try {
76 | var loader = new DefaultPreferencesLoader();
77 | loader.parseUri(
78 | "chrome://keyconfig-defaults/content/preferences/keyconfig.js");
79 | } catch (ex) {}
80 |
81 | if(event && event.eventPhase != 2) return;
82 |
83 | this.removeEventListener("pageshow",this.keyconfig.service.init,false);
84 |
85 | this.keyconfig.removedKeys = this.document.documentElement.appendChild(this.document.createElement("keyconfig"));
86 |
87 |
88 | if (this.keyconfig.service.ps.prefHasUserValue("keyconfig.global.20110522")) {
89 | var oldBranch = "keyconfig."; var newBranch = "extensions.dorandoKeyConfig.";
90 | var oldKeys = this.keyconfig.service.ps.getChildList(oldBranch)
91 | for (var i = 0; i < oldKeys.length; i++) {
92 | var newKey = newBranch + oldKeys[i].split(oldBranch)[1];
93 | switch (this.keyconfig.service.ps.getPrefType(oldKeys[i])) {
94 | case 32: //PREF_STRING
95 | var value = this.keyconfig.service.ps.getCharPref(oldKeys[i]);
96 | this.keyconfig.service.ps.setCharPref(newKey, value);
97 | break;
98 |
99 | case 64: //PREF_INT
100 | var value = this.keyconfig.service.ps.getIntPref(oldKeys[i]);
101 | this.keyconfig.service.ps.setIntPref(newKey, value);
102 | break;
103 |
104 | case 128: //PREF_BOOLEAN
105 | var value = this.keyconfig.service.ps.getBoolPref(oldKeys[i]);
106 | this.keyconfig.service.ps.setBoolPref(newKey, value);
107 | break;
108 | }
109 | }
110 | this.keyconfig.service.ps.deleteBranch(oldBranch);
111 | }
112 |
113 | this.keyconfig.service.ps.deleteBranch("extensions.dorandoKeyConfig.global")
114 |
115 | this.keyconfig.profile = "extensions.dorandoKeyConfig." + this.keyconfig.service.ps.getCharPref("extensions.dorandoKeyConfig.profile") + ".";
116 |
117 | var i, l;
118 |
119 | var keyset = this.document.getElementsByTagName("keyset")[0] ||
120 | this.document.documentElement.appendChild(this.document.createElement("keyset"));
121 |
122 | var nodes = this.document.getElementsByTagName("key");
123 | for(i = 0, l = nodes.length; i < l; i++) if(!nodes[i].id)
124 | nodes[i].id = "xxx_key"+ i +"_"+nodes[i].getAttribute("command")+nodes[i].getAttribute("oncommand");
125 |
126 | var keys = this.keyconfig.service.ps.getChildList(this.keyconfig.profile, {});
127 |
128 | for(i = 0, l = keys.length; i < l; i++) {
129 | var key, node;
130 | try {
131 | try {
132 | // Gecko 58+
133 | key = this.keyconfig.service.ps.getStringPref(keys[i]).split("][");
134 | }
135 | catch (e) {
136 | key = this.keyconfig.service.ps.getComplexValue(keys[i], Components.interfaces.nsISupportsString).data.split("][");
137 | }
138 | } catch(e) { continue; }
139 | if(key[3] && (!key[4] || key[4] == this.document.location)) {
140 | node = keyset.appendChild(this.document.createElement("key"));
141 | node.id = keys[i].substr(this.keyconfig.profile.length);
142 | // node.addEventListener("command",key[3]);
143 | node.setAttribute("oncommand",key[3])
144 | } else {
145 | node = this.document.getElementById(keys[i].substr(this.keyconfig.profile.length));
146 | if(!node) continue;
147 | }
148 |
149 | node.removeAttribute("modifiers"); node.removeAttribute("key"); node.removeAttribute("keycode");
150 | node.removeAttribute("charcode"); node.removeAttribute("keytext");
151 | if(key[0] == "!") {this.keyconfig.removedKeys.appendChild(node); continue;}
152 |
153 | if(key[0]) node.setAttribute("modifiers",key[0]);
154 | if(key[1]) node.setAttribute("key",key[1]);
155 | if(key[2]) node.setAttribute("keycode",key[2]);
156 | }
157 | },
158 |
159 | Module: function(module) { try {
160 | this.js.loadSubScript("chrome://keyconfig/content/" + module + ".js", this);
161 | } catch(err){} },
162 |
163 | Load: function(path) { try {
164 | this.js.loadSubScript(path, this);
165 | } catch(err){} }
166 |
167 | }
168 |
--------------------------------------------------------------------------------
/content/defaultPreferencesLoader.jsm:
--------------------------------------------------------------------------------
1 | // https://gist.github.com/oshybystyi/8cf882bc8b0c9a95a116
2 |
3 | /**
4 | * Working example can be found here
5 | * https://github.com/oshybystyi/FireX-Pixel-Perfect/blob/issue-5-make-addon-restartless/content/lib/defaultPreferencesLoader.jsm
6 | *
7 | * Important this module was tested only with true, most
8 | * likely it won't work with false value
9 | *
10 | * A lot of stuff was borrowed from https://github.com/firebug/firebug/blob/master/extension/modules/prefLoader.js
11 | */
12 |
13 | const { utils: Cu, classes: Cc, interfaces: Ci } = Components;
14 |
15 | Cu.import('resource://gre/modules/Services.jsm');
16 |
17 | var EXPORTED_SYMBOLS = ['DefaultPreferencesLoader'];
18 |
19 | /**
20 | * Read defaults/preferences/* and set Services.pref default branch
21 | */
22 | function DefaultPreferencesLoader(installPath, prefDir) {
23 | var readFrom = [];
24 |
25 | this.readFrom = readFrom;
26 |
27 | this.defaultBranch = Services.prefs.getDefaultBranch("");
28 |
29 | if (! installPath)
30 | // We'll be using parseUri instead of parseDirectory
31 | return;
32 |
33 | if (! prefDir)
34 | prefDir = 'defaults/preferences';
35 |
36 | // Maybe instead just test if it's a file rather than a directory?
37 | // Not sure.
38 | if (/\.xpi$/i.test(installPath.path)) {
39 | let baseURI = Services.io.newFileURI(installPath);
40 | // Packed extension, need to read ZIP to get list of preference files
41 | // and then use "jar:" URIs to access them.
42 | let zr = Cc['@mozilla.org/libjar/zip-reader;1'].createInstance(
43 | Ci.nsIZipReader);
44 | zr.open(installPath);
45 | let entries = zr.findEntries(prefDir + '/?*');
46 | while (entries.hasMore()) {
47 | let entry = entries.getNext();
48 | readFrom.push('jar:' + baseURI.spec + "!/" + entry);
49 | }
50 | }
51 | else {
52 | let dirPath = installPath.clone(); // don't modify the original object
53 |
54 | prefDir.split('/').forEach(function(dir) {
55 | dirPath.append(dir);
56 | });
57 |
58 | if (dirPath.exists() !== true) {
59 | throw new DefaultsDirectoryMissingError(dirPath);
60 | }
61 |
62 | let entries = dirPath.directoryEntries;
63 |
64 | while (entries.hasMoreElements()) {
65 | let fileURI = Services.io.newFileURI(entries.getNext());
66 | readFrom.push(fileURI.spec);
67 | }
68 | }
69 | }
70 |
71 | DefaultPreferencesLoader.prototype = {
72 | /**
73 | * Iterate over files in the default/preferences/*
74 | *
75 | * @param {function} prefFunc the function that should be used instead of
76 | * pref
77 | */
78 | parseDirectory: function(prefFunc) {
79 | this.readFrom.forEach(function(uri) {
80 | this.parseUri(uri, prefFunc);
81 | });
82 | },
83 |
84 | parseUri: function(uri, prefFunc) {
85 | prefFunc = prefFunc || this.pref.bind(this);
86 | Services.scriptloader.loadSubScript(uri, { pref: prefFunc });
87 | },
88 |
89 | /**
90 | * Emulates firefox pref function to load default preferences
91 | */
92 | pref: function(key, value) {
93 | switch (typeof value) {
94 | case 'boolean':
95 | this.defaultBranch.setBoolPref(key, value);
96 | break;
97 |
98 | case 'number':
99 | this.defaultBranch.setIntPref(key, value);
100 | break;
101 |
102 | case 'string':
103 | this.defaultBranch.setStringPref(key, value);
104 | break;
105 |
106 | default:
107 | throw new NotSupportedValueTypeError(key);
108 | break;
109 | }
110 | },
111 |
112 | /**
113 | * Clears default preferences according to AMO reviewers reccommendation
114 | * This should be invoked on bootstrap::shutdown
115 | * @see https://github.com/firebug/firebug/blob/master/extension/modules/prefLoader.js
116 | */
117 | clearDefaultPrefs: function() {
118 | this.parseDirectory(this.prefUnload.bind(this));
119 | },
120 |
121 | prefUnload: function(key) {
122 | let branch = this.defaultBranch;
123 | if (branch.prefHasUserValue(key) !== true) {
124 | branch.deleteBranch(key);
125 | }
126 | }
127 |
128 | };
129 |
130 | /**
131 | * Exception type on missing defaults/preferences folder
132 | */
133 | function DefaultsDirectoryMissingError(installPath) {
134 | this.name = 'DefaultsDirectoryMissingError';
135 | this.message = '\'' + installPath.path + '\' does no exist';
136 | }
137 |
138 | /** Inherit from Error for error stack and pretty output in terminal **/
139 | DefaultsDirectoryMissingError.prototype = new Error();
140 |
141 | /**
142 | * Not supported value type to store by pref
143 | */
144 | function NotSupportedValueTypeError(key) {
145 | this.name = 'NotSupportedValueType';
146 | this.message = 'Value type for key \'' + key + '\' is not supported';
147 | }
148 |
149 | NotSupportedValueTypeError.prototype = new Error();
150 |
--------------------------------------------------------------------------------
/content/edit.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
46 |
--------------------------------------------------------------------------------
/content/keyconfig.js:
--------------------------------------------------------------------------------
1 | var gPrefService = Components.classes['@mozilla.org/preferences-service;1']
2 | .getService(Components.interfaces.nsIPrefService).getBranch("");
3 | var gUnicodeConverter = Components.classes['@mozilla.org/intl/scriptableunicodeconverter']
4 | .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
5 | var gClipboardHelper = Components.classes["@mozilla.org/widget/clipboardhelper;1"]
6 | .getService(Components.interfaces.nsIClipboardHelper);
7 | var WindowMediator = Components.classes['@mozilla.org/appshell/window-mediator;1']
8 | .getService(Components.interfaces.nsIWindowMediator);
9 |
10 | var gDocument, gLocation, gProfile, gKeys, gUsedKeys, gRemovedKeys;
11 |
12 | var gExtra2, keyTree, gEditbox, gEdit;
13 |
14 | var gLocaleKeys;
15 | var gPlatformKeys = new Object();
16 | var gVKNames = [];
17 | var gReverseNames;
18 |
19 | function onLoad() {
20 | gUnicodeConverter.charset = "UTF-8";
21 |
22 | gExtra2 = document.documentElement.getButton("extra2");
23 | keyTree = document.getElementById("key-tree");
24 | gEditbox = document.getElementById("editbox");
25 | gEdit = document.getElementById("edit");
26 | gLocaleKeys = document.getElementById("localeKeys");
27 |
28 | var platformKeys = document.getElementById("platformKeys");
29 | gPlatformKeys.shift = platformKeys.getString("VK_SHIFT");
30 | gPlatformKeys.meta = platformKeys.getString("VK_META");
31 | gPlatformKeys.alt = platformKeys.getString("VK_ALT");
32 | gPlatformKeys.ctrl = platformKeys.getString("VK_CONTROL");
33 | gPlatformKeys.sep = platformKeys.getString("MODIFIER_SEPARATOR");
34 | switch (gPrefService.getIntPref("ui.key.accelKey")){
35 | case 17: gPlatformKeys.accel = gPlatformKeys.ctrl; break;
36 | case 18: gPlatformKeys.accel = gPlatformKeys.alt; break;
37 | case 224: gPlatformKeys.accel = gPlatformKeys.meta; break;
38 | default: gPlatformKeys.accel = (window.navigator.platform.search("Mac") == 0 ? gPlatformKeys.meta : gPlatformKeys.ctrl);
39 | }
40 |
41 | for (var property in KeyEvent) {
42 | gVKNames[KeyEvent[property]] = property.replace("DOM_","");
43 | }
44 | gVKNames[8] = "VK_BACK";
45 |
46 | var XULAppInfo = Components.classes["@mozilla.org/xre/app-info;1"].getService(Components.interfaces.nsIXULAppInfo);
47 | var isThunderbird = XULAppInfo.name == "Thunderbird";
48 |
49 | gReverseNames = isThunderbird ^ gPrefService.getBoolPref("extensions.dorandoKeyConfig.nicenames.reverse_order");
50 |
51 | if(gPrefService.getBoolPref("extensions.dorandoKeyConfig.devmode")){ this.getFormattedKey = function(a,b,c) {return (a+"+"+b+c).replace(/null/g,"");} }
52 |
53 | var target = window.arguments ? window.arguments[0] : WindowMediator.getEnumerator(null).getNext();
54 |
55 | var windowList = document.getElementById("window-list");
56 | var i, l;
57 | for(i = 0, l = windowList.firstChild.childNodes.length; i < l; i++)
58 | if(windowList.firstChild.childNodes[i].label == target.document.title)
59 | windowList.selectedIndex = i;
60 |
61 | init(target);
62 |
63 | windowList.focus();
64 | }
65 |
66 | function init(target) {
67 | if(!target) return;
68 |
69 | gDocument = target.document;
70 | gLocation = gDocument.location.href;
71 | gProfile = target.keyconfig.profile;
72 |
73 | gKeys = [];
74 | gRemovedKeys = target.keyconfig.removedKeys;
75 |
76 | var hideDisabled = gPrefService.getBoolPref("extensions.dorandoKeyConfig.hideDisabled");
77 |
78 | var keys = gDocument.getElementsByTagName("key");
79 | for(var i = 0, l = keys.length; i < l; i++) {
80 | var key = new Key(keys[i]);
81 | if(!(hideDisabled && key.disabled))
82 | gKeys.push(key);
83 | }
84 |
85 | detectUsedKeys();
86 |
87 | var elem = keyTree.getElementsByAttribute("sortActive","true")[0] || document.getElementById("name");
88 |
89 | gKeys.sort(sorter[elem.id]);
90 | if(elem.getAttribute("sortDirection") == "descending") gKeys.reverse();
91 |
92 | keyTree.view = keyView;
93 | keyTree.view.selection.select(-1);
94 |
95 | gExtra2.label = gStrings.add;
96 | gEditbox.setAttribute("disabled","true");
97 | gEdit.value = "";
98 | gEdit.keys = ["!",null,null];
99 | }
100 |
101 | function onOK() { }
102 |
103 | function getFormattedKey(modifiers,key,keycode) {
104 | if(modifiers == "shift,alt,control,accel" && keycode == "VK_SCROLL_LOCK") return gStrings.disabled;
105 | if(!key && !keycode) return gStrings.disabled;
106 |
107 | var val = "";
108 | if(modifiers) val = modifiers
109 | .replace(/^[\s,]+|[\s,]+$/g,"").split(/[\s,]+/g).join(gPlatformKeys.sep)
110 | .replace("alt",gPlatformKeys.alt)
111 | .replace("shift",gPlatformKeys.shift)
112 | .replace("control",gPlatformKeys.ctrl)
113 | .replace("meta",gPlatformKeys.meta)
114 | .replace("accel",gPlatformKeys.accel)
115 | +gPlatformKeys.sep;
116 | if(key == " ") {
117 | key = ""; keycode = "VK_SPACE";
118 | }
119 | if(key)
120 | val += key;
121 | if(keycode) try {
122 | val += gLocaleKeys.getString(keycode)
123 | } catch(e){val += gStrings.unrecognized.replace("$1",keycode);}
124 |
125 | return val;
126 | }
127 |
128 | function getNameForKey(aKey) {
129 | var val;
130 |
131 | if(aKey.hasAttribute("label")) return aKey.getAttribute("label");
132 |
133 | if(aKey.hasAttribute("command") || aKey.hasAttribute("observes")) {
134 | var command = aKey.getAttribute("command") || aKey.getAttribute("observes");
135 | var node = gDocument.getElementById(command);
136 | if(node && node.hasAttribute("label")) return node.getAttribute("label");
137 | val = getLabel("command", command);
138 | if(!val) val = getLabel("observes", command);
139 | }
140 |
141 | if(!val) val = getLabel("key", aKey.id);
142 |
143 | if(val) return val;
144 |
145 | var id = aKey.id.replace(/xxx_key.+?_/,"");
146 | try {id = gUnicodeConverter.ConvertToUnicode(id);} catch(err) { gUnicodeConverter.charset = "UTF-8"; }
147 |
148 | if(keyname[id]) {
149 | var key = gDocument.getElementById(keyname[id]);
150 | if(key) return getNameForKey(key);
151 | return keyname[id];
152 | }
153 |
154 | return id;
155 | }
156 |
157 | function getLabel(attr, value) {
158 | var Users = gDocument.getElementsByAttribute(attr,value);
159 | var User;
160 |
161 | for(var i = 0, l = Users.length; i < l; i++)
162 | if(Users[i].hasAttribute("label") && (!User || User.localName == "menuitem")) User = Users[i];
163 |
164 | if(!User) return null;
165 |
166 | if(User.localName == "menuitem" && User.parentNode.parentNode.parentNode.localName == "menupopup") {
167 | if(gReverseNames) return User.parentNode.parentNode.getAttribute("label") + " > " + User.getAttribute("label");
168 | else return User.getAttribute("label") + " [" + User.parentNode.parentNode.getAttribute("label") + "]";
169 | } else return User.getAttribute("label");
170 | }
171 |
172 | function Recognize(event) {
173 | event.preventDefault();
174 | event.stopPropagation();
175 |
176 | var modifiers = [];
177 | if(event.altKey) modifiers.push("alt");
178 | if(event.ctrlKey) modifiers.push("control");
179 | if(event.metaKey) modifiers.push("meta");
180 | if(event.shiftKey) modifiers.push("shift");
181 |
182 | modifiers = modifiers.join(" ");
183 |
184 | var key = null; var keycode = null;
185 | if(event.charCode) key = String.fromCharCode(event.charCode).toUpperCase();
186 | else { keycode = gVKNames[event.keyCode]; if(!keycode) return;}
187 |
188 | gEdit.value = getFormattedKey(modifiers,key,keycode);
189 | gEdit.keys = [modifiers,key,keycode];
190 |
191 | if(!(gPrefService.getBoolPref("extensions.dorandoKeyConfig.allowAltCodes") && modifiers == "alt" && key && !isNaN(key))) {
192 | if(gPrefService.getBoolPref("extensions.dorandoKeyConfig.warnOnDuplicate") && gEdit.value != gEdit.key.shortcut && gUsedKeys[gEdit.value])
193 | window.setTimeout(function(){ window.alert(gStrings.used.replace("$1",gUsedKeys[gEdit.value].join("\n"))) },0);
194 |
195 | gEdit.nextSibling.focus();
196 | }
197 | }
198 |
199 | function Apply() {
200 | var key = gKeys[keyTree.currentIndex];
201 |
202 | keyTree.focus();
203 |
204 | if(key.shortcut == gEdit.value) return;
205 |
206 | key.shortcut = gEdit.value;
207 | key.pref.splice(0,3,gEdit.keys[0],gEdit.keys[1],gEdit.keys[2]);
208 |
209 | detectUsedKeys();
210 |
211 | var value = key.pref.join("][");
212 | try {
213 | // Gecko 58+
214 | gPrefService.setStringPref(gProfile+key.id, value);
215 | }
216 | catch (e) {
217 | var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
218 | str.data = value;
219 | gPrefService.setComplexValue(gProfile+key.id, Components.interfaces.nsISupportsString, str);
220 | }
221 |
222 | keyTree.treeBoxObject.invalidate();
223 |
224 | var targets = WindowMediator.getEnumerator(null);
225 | var target;
226 | while(target = targets.getNext()) {
227 | if(key.pref[4] && target.location != key.pref[4])
228 | continue;
229 |
230 | var node = target.document.getElementById(key.id);
231 | if(node) {
232 | node.removeAttribute("modifiers"); node.removeAttribute("key"); node.removeAttribute("keycode");
233 | node.removeAttribute("charcode"); node.removeAttribute("keytext");
234 | node.removeAttribute("keyconfig");
235 |
236 | var keyset = null;
237 |
238 | if(key.pref[0] == "!") {
239 | keyset = node.parentNode;
240 | target.keyconfig.removedKeys.appendChild(node);
241 | } else {
242 | if(key.pref[0]) node.setAttribute("modifiers",key.pref[0]);
243 | if(key.pref[1]) node.setAttribute("key",key.pref[1]);
244 | if(key.pref[2]) node.setAttribute("keycode",key.pref[2]);
245 |
246 | if(node.parentNode.localName != "keyset")
247 | target.document.getElementsByTagName("keyset")[0].appendChild(node);
248 | }
249 |
250 | keyset = keyset || node.parentNode;
251 | while(keyset.parentNode && keyset.parentNode.localName == "keyset")
252 | keyset = keyset.parentNode;
253 | keyset.parentNode.insertBefore(keyset, keyset.nextSibling);
254 |
255 | var menuitems = target.document.getElementsByAttribute("key",key.id);
256 | for(var i = 0, l = menuitems.length; i < l; i++) {
257 | menuitems[i].setAttribute("acceltext","");
258 | menuitems[i].removeAttribute("acceltext");
259 | }
260 | }
261 | }
262 | }
263 |
264 | function Disable() {
265 | gEdit.value = gStrings.disabled;
266 | gEdit.keys = ["!",null,null];
267 | Apply();
268 | }
269 |
270 | function Reset() {
271 | var key = gKeys[keyTree.currentIndex];
272 |
273 | try{ gPrefService.clearUserPref(gProfile+key.id); } catch(err) {}
274 |
275 | key.pref = [];
276 | key.shortcut = gEdit.value = gStrings.uponreset;
277 | gEdit.keys = ["!",null,null];
278 |
279 | gExtra2.label = gStrings.add;
280 |
281 | var targets = WindowMediator.getEnumerator(null);
282 | var target;
283 | while(target = targets.getNext()) {
284 | var node = target.document.getElementById(key.id);
285 | if(node)
286 | node.setAttribute("keyconfig","resetted");
287 | }
288 |
289 | detectUsedKeys();
290 |
291 | keyTree.treeBoxObject.invalidate();
292 | keyTree.focus();
293 | }
294 |
295 | function Key(aKey) {
296 | this.name = getNameForKey(aKey);
297 | this.shortcut = getFormattedKey(
298 | aKey.hasAttribute("modifiers") ? aKey.getAttribute("modifiers") : null,
299 | aKey.hasAttribute("keytext") ? aKey.getAttribute("keytext") :
300 | aKey.hasAttribute("key") ? aKey.getAttribute("key").toUpperCase() : aKey.hasAttribute("charcode") ? aKey.getAttribute("charcode").toUpperCase() : null,
301 | aKey.hasAttribute("keycode") ? aKey.getAttribute("keycode") : null
302 | );
303 | this.id = aKey.id;
304 | if(aKey.getAttribute("keyconfig") == "resetted") this.shortcut = gStrings.uponreset;
305 |
306 | try {
307 | try {
308 | // Gecko 58+
309 | this.pref = gPrefService.getStringPref(gProfile+aKey.id).split("][");
310 | }
311 | catch (e) {
312 | this.pref = gPrefService.getComplexValue(gProfile+aKey.id, Components.interfaces.nsISupportsString).data.split("][");
313 | }
314 | } catch(err) { this.pref = []; }
315 |
316 | this.code = getCodeFor(aKey);
317 | if(this.code == null) this.hardcoded = true;
318 | }
319 | Key.prototype = {
320 | get disabled() { return this.shortcut == gStrings.disabled; }
321 | }
322 |
323 | var sorter = {
324 | name: function(a,b) { return a.name.localeCompare(b.name); },
325 | id: function(a,b) { return a.id.localeCompare(b.id); },
326 | shortcut: function(a,b) {
327 | if(a.shortcut == b.shortcut) return 0;
328 | if(!a.shortcut) return 1;
329 | if(!b.shortcut) return -1;
330 | if(a.shortcut > b.shortcut) return 1;
331 | return -1;
332 | }
333 | }
334 |
335 | function detectUsedKeys() {
336 | gUsedKeys = [];
337 |
338 | for(var i = 0, l = gKeys.length; i < l; i++) {
339 | if(gUsedKeys[gKeys[i].shortcut])
340 | gUsedKeys[gKeys[i].shortcut].push(gKeys[i].name);
341 | else
342 | gUsedKeys[gKeys[i].shortcut]=[gKeys[i].name];
343 | }
344 |
345 | gUsedKeys[gStrings.disabled] = gUsedKeys[gStrings.uponreset] = {length: 0}
346 | }
347 |
348 | function openEditor(type) {
349 | var key, code;
350 | switch(type) {
351 | case 1:
352 | key = gKeys[keyTree.currentIndex];
353 | break;
354 | case 2:
355 | key = gKeys[keyTree.currentIndex];
356 | if(key && !key.pref[3]) code = key.code;
357 | break;
358 | }
359 |
360 | openDialog('chrome://keyconfig/content/edit.xul', '_blank', 'resizable,modal', key, code, this);
361 | }
362 |
363 | function closeEditor(fields) {
364 | var key;
365 |
366 | if(fields.key) {
367 | key = fields.key;
368 | gPrefService.clearUserPref(gProfile+key.id);
369 | } else {
370 | key = { shortcut: gStrings.disabled, pref: ["!",null,null," "] }
371 | gKeys.push(key);
372 |
373 | keyTree.treeBoxObject.rowCountChanged(keyTree.view.rowCount-1,1);
374 | keyTree.view.selection.select(keyTree.view.rowCount-1);
375 | keyTree.treeBoxObject.ensureRowIsVisible(keyTree.view.rowCount-1);
376 | gEdit.focus();
377 | }
378 |
379 | var currentId = key.id;
380 |
381 | if(key.name != fields.name.value) try {
382 | key.name = fields.name.value || "key"+Date.now();
383 |
384 | var i = 1;
385 | do {
386 | key.id = "xxx_key"+(i++)+"_" + gUnicodeConverter.ConvertFromUnicode(key.name);
387 | } while(gPrefService.prefHasUserValue(gProfile+key.id));
388 | } catch(err){ gUnicodeConverter.charset = "UTF-8"; key.id = "key"+Date.now(); }
389 |
390 | key.code = key.pref[3] = fields.code.value.replace(/]\[/g,"] [") || " ";
391 |
392 | key.pref[4] = fields.global.checked ? "" : gLocation;
393 |
394 | var value = key.pref.join("][");
395 | try {
396 | // Gecko 58+
397 | gPrefService.setStringPref(gProfile+key.id, value);
398 | }
399 | catch (e) {
400 | var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
401 | str.data = value;
402 | gPrefService.setComplexValue(gProfile+key.id, Components.interfaces.nsISupportsString, str);
403 | }
404 |
405 | var targets = WindowMediator.getEnumerator(null);
406 | var target;
407 | while(target = targets.getNext()) {
408 | if(key.pref[4] && target.location != key.pref[4])
409 | continue;
410 |
411 | var node = target.document.getElementById(currentId);
412 | if(!node)
413 | node = target.keyconfig.removedKeys.appendChild(target.document.createElement("key"));
414 |
415 | node.id = key.id;
416 | //node.addEventListener("command",key.code);
417 | node.setAttribute("oncommand",key.code);
418 |
419 | }
420 |
421 | keyTree.treeBoxObject.invalidateRow(keyTree.currentIndex);
422 | }
423 |
424 | var keyView = {
425 | get rowCount() { return gKeys.length; },
426 | getCellText : function(row,col){ return gKeys[row][col.id || col];},
427 | setTree: function(treebox) { this.treebox=treebox; },
428 | isContainer: function() { return false; },
429 | isSeparator: function() { return false; },
430 | isSorted: function() { return false; },
431 | getLevel: function() { return 0; },
432 | getImageSrc: function() { return null; },
433 | getRowProperties: function(row, prop) { this.getCellProperties(row, "", prop); },
434 | canDropBeforeAfter: function() { return false; },
435 | canDrop: function() { return false; },
436 | getParentIndex: function() { return -1; },
437 |
438 | getCellProperties: function(row,col) {
439 | var key = gKeys[row];
440 | // try { console.log ( key + " " + key.shortcut ) } catch(e) {};
441 | //try { if (key.shortcut ) return "reset"; } catch(e) {console.log(e)}
442 | if(key.hardcoded) return "hardcoded";
443 | if(key.disabled) return "disabled";
444 | if(key.pref[3]) return "custom";
445 | if(key.pref.length) return "user";
446 | if((col.id || col) == "shortcut" && gUsedKeys[key.shortcut].length > 1)
447 | return "duplicate";
448 | return "";
449 | },
450 | getColumnProperties: function(){},
451 | selectionChanged: function() {
452 | var key = gKeys[this.selection.currentIndex];
453 |
454 | if(!key) return;
455 |
456 | gExtra2.label = key.pref[3] ? gStrings.edit : gStrings.add;
457 | if(gEditbox.hasAttribute("disabled")) gEditbox.removeAttribute("disabled");
458 | gEdit.key = key;
459 | gEdit.value = key.shortcut;
460 | },
461 | cycleHeader: function cycleHeader(col, elem) {
462 | if(col.id) elem = col.element;
463 |
464 | var direction = elem.getAttribute("sortDirection") == "ascending" ? "descending" : "ascending";
465 | var columns = this.treebox.firstChild.childNodes;
466 | for(var i = 0, l = columns.length; i < l; i++) {
467 | columns[i].setAttribute("sortDirection","none");
468 | columns[i].setAttribute("sortActive",false);
469 | }
470 |
471 | elem.setAttribute("sortDirection",direction);
472 | elem.setAttribute("sortActive",true);
473 |
474 | var currentRow = gKeys[this.selection.currentIndex];
475 |
476 | gKeys.sort(sorter[col.id || col]);
477 | if(direction == "descending") gKeys.reverse();
478 |
479 | this.treebox.invalidate();
480 | if(currentRow) {
481 | i = -1;
482 | do { i++; } while(currentRow != gKeys[i]);
483 | this.selection.select(i);
484 | this.treebox.ensureRowIsVisible(i);
485 | }
486 | }
487 | }
488 |
489 | function switchWindow(event) {
490 | var mediator = Components.classes["@mozilla.org/rdf/datasource;1?name=window-mediator"].getService();
491 | mediator.QueryInterface(Components.interfaces.nsIWindowDataSource);
492 |
493 | var target = mediator.getWindowForResource(event.target.getAttribute('id'));
494 |
495 | if (target) init(target);
496 | }
497 |
498 | function getCodeFor(node) {
499 | if(node.hasAttribute("oncommand")) {
500 | return node.getAttribute("oncommand");
501 | } else if(node.hasAttribute("command")) {
502 | var command = gDocument.getElementById(node.getAttribute("command"));
503 | if(command) return command.getAttribute("oncommand");
504 | } else if(node.hasAttribute("observes")) {
505 | var observer = gDocument.getElementById(node.getAttribute("observes"));
506 | if(observer) return command.getAttribute("oncommand");
507 | }
508 | return null;
509 | }
510 |
511 | function copyKey() {
512 | var key = gKeys[keyTree.currentIndex];
513 | if(!key) return;
514 |
515 | var data = 'name: ' + key.name + ', id: ' + key.id + ', shortcut: ' + key.shortcut + ', code:\n' + key.code;
516 |
517 | gClipboardHelper.copyString(data);
518 | }
519 |
--------------------------------------------------------------------------------
/content/keyconfig.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 | %keyconfig; %textcontext;
9 | ]>
10 |
11 |
91 |
--------------------------------------------------------------------------------
/content/menumanipulator.js:
--------------------------------------------------------------------------------
1 | if(!document.getElementById("keyconfig") &&
2 | this.document.location.href.match(this.document.defaultView.keyconfig.service.ps.getCharPref("keyconfig.UIHook"))) {
3 | New("menuitem","keyconfig");
4 | Move(
5 | "id('menu_ToolsPopup') | id('tools-menu')/x:menupopup | //x:menu[@label='Tools']/x:menupopup",0,[
6 | "id('taskPopup') | id('tasksMenu')/x:menupopup",0,
7 | "//x:menubar//x:menu/x:menupopup",0,
8 | "id('contentAreaContextMenu')",0
9 | ]);
10 | Set("label","Keyconfig\u2026");
11 | Set("key","key_keyconfig");
12 | Set("oncommand","openDialog('chrome://keyconfig/content/', '_blank', 'resizable', window);");
13 |
14 | delete this.node.menumanipulator;
15 | }
16 |
--------------------------------------------------------------------------------
/content/overlay.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/defaults/preferences/keyconfig.js:
--------------------------------------------------------------------------------
1 | pref("extensions.dorandoKeyConfig.devmode", false);
2 | pref("extensions.dorandoKeyConfig.nicenames.reverse_order", false);
3 | pref("extensions.dorandoKeyConfig.profile", "main");
4 | pref("extensions.dorandoKeyConfig.warnOnDuplicate", true);
5 | pref("extensions.dorandoKeyConfig.allowAltCodes", true);
6 | pref("extensions.dorandoKeyConfig.hideDisabled", false);
7 |
--------------------------------------------------------------------------------
/functions_for_keyconfig-1.3.7-fx.xpi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trlkly/dorando-keyconfig/2d30ec4c340877586d52722eae7c484baecd75c2/functions_for_keyconfig-1.3.7-fx.xpi
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trlkly/dorando-keyconfig/2d30ec4c340877586d52722eae7c484baecd75c2/icon.png
--------------------------------------------------------------------------------
/icon64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trlkly/dorando-keyconfig/2d30ec4c340877586d52722eae7c484baecd75c2/icon64.png
--------------------------------------------------------------------------------
/install.rdf:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | keyconfig@mozilla.dorando.at
8 | Dorando keyconfig
9 | 2018.1
10 | Dorando
11 | Hadar Hagai
12 | trlkly
13 | Jonathan Kamens
14 | MatrixIsAllOver of eXtenZilla.it (it-IT)
15 | Mori (fr-FR)
16 | SHIMODA Hiroshi (ja-JP)
17 | SlovakSoft (sk-SK)
18 | Tomáš Kopečný (cs-CZ)
19 | ReinekeFux - erweiterungen.de (de-DE)
20 | stoneflash (ru-RU)
21 | ZuGro (es-AR)
22 | rexx26 (zh-TW)
23 | kyo (ko-KR)
24 | Cye3s (zh-CN)
25 | Jørgen Rasmussen (da-DK)
26 | Jack Black (fr-FR)
27 | http://mozilla.dorando.at/
28 | Rebind your keys.
29 | chrome://keyconfig/content/
30 | 3
31 | 2
32 | true
33 |
34 |
35 | {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
36 | 4.0
37 | 56.*
38 |
39 |
40 |
41 | {3550f703-e582-4d05-9a08-453d09bdfdc6}
42 | 5.0b1
43 | 61.0
44 |
45 |
46 |
47 | {aa3c5121-dab2-40e2-81ca-7ea25febc110}
48 | 10.0a1
49 | 56.*
50 |
51 |
52 |
53 | {a23983c0-fd0e-11dc-95ff-0800200c9a66}
54 | 4.0
55 | 56.*
56 |
57 |
58 |
59 | {92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}
60 | 2.1
61 | 2.49.*
62 |
63 |
64 |
65 | {8de7fcbb-c55c-4fbe-bfc5-fc555c87dbc4}
66 | 25.0
67 | 27.*
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/locale/cs-CZ/keyconfig.ent:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ">
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ">
18 |
--------------------------------------------------------------------------------
/locale/da-DK/keyconfig.ent:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ">
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ">
18 |
--------------------------------------------------------------------------------
/locale/de-DE/keyconfig.ent:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ">
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ">
18 |
--------------------------------------------------------------------------------
/locale/en-US/keyconfig.ent:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ">
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ">
18 |
--------------------------------------------------------------------------------
/locale/es-AR/keyconfig.ent:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ">
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ">
18 |
--------------------------------------------------------------------------------
/locale/fr-FR/keyconfig.ent:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ">
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ">
18 |
--------------------------------------------------------------------------------
/locale/it-IT/keyconfig.ent:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ">
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ">
18 |
--------------------------------------------------------------------------------
/locale/ja-JP/keyconfig.ent:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ">
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ">
18 |
--------------------------------------------------------------------------------
/locale/ko-KR/keyconfig.ent:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ">
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ">
18 |
--------------------------------------------------------------------------------
/locale/ru-RU/keyconfig.ent:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ">
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ">
18 |
--------------------------------------------------------------------------------
/locale/sk-SK/keyconfig.ent:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ">
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ">
18 |
--------------------------------------------------------------------------------
/locale/zh-CN/keyconfig.ent:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ">
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ">
18 |
--------------------------------------------------------------------------------
/locale/zh-TW/keyconfig.ent:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | ">
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ">
18 |
--------------------------------------------------------------------------------
/skin/keyconfig.css:
--------------------------------------------------------------------------------
1 | treechildren::-moz-tree-cell-text(hardcoded) {
2 | color: darkorange;
3 | }
4 |
5 | treechildren::-moz-tree-cell-text(disabled) {
6 | color: red;
7 | }
8 |
9 | treechildren::-moz-tree-cell-text(custom) {
10 | color: magenta;
11 | }
12 |
13 | treechildren::-moz-tree-cell-text(user) {
14 | color: deepskyblue;
15 | }
16 |
17 | treechildren::-moz-tree-cell-text(duplicate) {
18 | background-color: Highlight;
19 | color: HighlightText !important;
20 | }
21 |
22 | treechildren::-moz-tree-cell-text(selected, duplicate) {
23 | background-color: HighlightText;
24 | color: Highlight !important;
25 | }
26 |
27 | treechildren::-moz-tree-cell-text(reset) {
28 | color: blue
29 | }
--------------------------------------------------------------------------------