// ==UserScript== // @name Duolingo input language switcher // @namespace https://www.duolingo.com/IVrL9 // @author T1mL3arn // @match https://www.duolingo.com/* // @match https://www.example.com/* // @match https://example.com/* // @version 1.4.1 // @description This script allows you to type letters appropriate for current task without changing keyboard's layout // @run-at document-start // @grant none // @license GPLv3 // @homepageURL https://github.com/T1mL3arn/Duolingo-input-language-switcher // @supportURL https://greasyfork.org/en/scripts/37693-duolingo-input-language-switcher/feedback // @downloadURL none // ==/UserScript==//// Generated by Haxe 3.4.7 (function () { "use strict"; var HxOverrides = function() { }; HxOverrides.substr = function(s,pos,len) { if(len == null) { len = s.length; } else if(len < 0) { if(pos == 0) { len = s.length + len; } else { return ""; } } return s.substr(pos,len); }; var Main = function() { this.document = window.document; this.console = { }; this.initLanguages(); if(this.document.readyState == "interactive" || this.document.readyState == "complete") { this.onready(); } else { this.document.addEventListener("DOMContentLoaded",$bind(this,this.onready)); } }; Main.main = function() { new Main(); }; Main.prototype = { initLanguages: function() { this.keyCodes = ["Backquote","Digit1","Digit2","Digit3","Digit4","Digit5","Digit6","Digit7","Digit8","Digit9","Digit0","Minus","Equal","Backslash","KeyQ","KeyW","KeyE","KeyR","KeyT","KeyY","KeyU","KeyI","KeyO","KeyP","BracketLeft","BracketRight","KeyA","KeyS","KeyD","KeyF","KeyG","KeyH","KeyJ","KeyK","KeyL","Semicolon","Quote","KeyZ","KeyX","KeyC","KeyV","KeyB","KeyN","KeyM","Comma","Period","Slash"]; this.languages = { }; this.languages.ru = "ё1234567890-=\\йцукенгшщзхъфывапролджэячсмитьбю.Ё!\"№;%:?*()_+/ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,"; this.languages.en = "`1234567890-=\\qwertyuiop[]asdfghjkl;'zxcvbnm,./~!@#$%^&*()_+|QWERTYUIOP{}ASDFGHJKL:\"ZXCVBNM<>?"; var len = this.languages.ru.length; var _g = 0; var _g1 = Reflect.fields(this.languages); while(_g < _g1.length) { var f = _g1[_g]; ++_g; var act = this.languages[f].length; if(act != len) { this.console.error("LangString test failed: expected len " + len + "; actual len " + act + "; lang name " + f); this.console.error(this.languages[f]); return; } if(act != this.keyCodes.length * 2) { this.console.error("KeyCodes and LangString test failed: expected lang string len " + this.keyCodes.length * 2 + "; actual len " + act + "; lang name " + f); return; } } } ,onready: function(e) { this.document.removeEventListener("DOMContentLoaded",$bind(this,this.onready)); this.console.log("Duolingo input switcher is ready"); window.document.body.addEventListener("keypress",$bind(this,this.onKeyPress)); window.document.body.addEventListener("keydown",$bind(this,this.refocus)); } ,onKeyPress: function(e) { if(e.ctrlKey) { return; } var sourceElt = e.target; if(this.isInput(sourceElt)) { var challengeType = sourceElt.dataset.test; switch(challengeType) { case "challenge-listen-input":case "challenge-listentap-input":case "challenge-name-input": this.setLanguagePair("en","ru"); break; case "challenge-translate-input": this.nativeLanguage = "ru"; this.foreignLanguage = "en"; var lang = sourceElt.getAttribute("lang"); if(lang == this.nativeLanguage) { this.setLanguagePair("ru","en"); } else if(lang == this.foreignLanguage) { this.setLanguagePair("en","ru"); } break; default: return; } var targetLangStr = this.languages[this.targetLanguage]; var keyCodeInd = this.keyCodes.indexOf(e.code); if(keyCodeInd != -1) { var targetChar = e.shiftKey ? targetLangStr.charAt(keyCodeInd + this.keyCodes.length) : targetLangStr.charAt(keyCodeInd); var input = sourceElt; window.setTimeout($bind(this,this.replaceChar),1,input,targetChar,input.selectionStart); } } } ,isInput: function(elt) { if(elt.tagName != "TEXTAREA") { if(elt.tagName == "INPUT") { return elt.getAttribute("type") == "text"; } else { return false; } } else { return true; } } ,setLanguagePair: function(target,source) { this.targetLanguage = target; this.sourceLanguage = source; } ,refocus: function(e) { if(this.isInput(e.target)) { if(e.keyCode == 13 || e.code == "Enter") { e.target.blur(); } } } ,replaceChar: function(target,newChar,position) { var val = target.value; val = val.substring(0,position) + newChar + HxOverrides.substr(val,position + 1,null); target.innerText = val; target.value = val; target.setSelectionRange(position + 1,position + 1); } }; var Reflect = function() { }; Reflect.fields = function(o) { var a = []; if(o != null) { var hasOwnProperty = Object.prototype.hasOwnProperty; for( var f in o ) { if(f != "__id__" && f != "hx__closures__" && hasOwnProperty.call(o,f)) { a.push(f); } } } return a; }; var $_, $fid = 0; function $bind(o,m) { if( m == null ) return null; if( m.__id__ == null ) m.__id__ = $fid++; var f; if( o.hx__closures__ == null ) o.hx__closures__ = {}; else f = o.hx__closures__[m.__id__]; if( f == null ) { f = function(){ return f.method.apply(f.scope, arguments); }; f.scope = o; f.method = m; o.hx__closures__[m.__id__] = f; } return f; } Main.main(); })();