Created
February 19, 2010 04:07
-
-
Save nanto/308409 to your computer and use it in GitHub Desktop.
A userChrome.js script to read selected text with js-ctypes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Read Selection | |
// @namespace http://nanto.asablo.jp/blog/ | |
// @description Read selection text. | |
// @include chrome://browser/content/browser.xul | |
// @author nanto_vi | |
// ==/UserScript== | |
({ | |
// http://www.a-quest.com/products/aquestalk2.html | |
AQUES_TALK_2_DA_PATH: 'C:\\AquesTalk2\\bin\\AquesTalk2Da.dll', | |
// http://kakasi.namazu.org/ | |
KAKASI_PATH: 'C:\\kakasi\\lib\\kakasi.dll', | |
CRT_PATH: 'msvcr71', | |
READ_SELECTION_LABEL: '選択範囲のテキストを読み上げ', | |
READ_SELECTION_KEY: 'R', | |
NATIVE_ENCODING: 'Shift_JIS', | |
menuitem: null, | |
init: function RS_init() { | |
default xml namespace = | |
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; | |
let range = document.createRange(); | |
range.setStartBefore(document.getElementById('context-sep-viewsource')); | |
range.collapse(true); | |
let label = this.READ_SELECTION_LABEL; | |
let key = this.READ_SELECTION_KEY; | |
if ('あ'.length !== 1) { | |
label = this.decode(label, 'UTF-8'); | |
key = this.decode(key, 'UTF-8'); | |
} | |
let menuitem = range.createContextualFragment( | |
<menuitem label={ label } accesskey={ key }/>.toXMLString() | |
).firstChild; | |
range.insertNode(menuitem); | |
menuitem.addEventListener('command', this, false); | |
menuitem.parentNode.addEventListener('popupshowing', this, false); | |
this.menuitem = menuitem; | |
}, | |
handleEvent: function RS_handleEvent(event) { | |
switch (event.type) { | |
case 'command': | |
this.read(getBrowserSelection()); | |
break; | |
case 'popupshowing': | |
this.menuitem.collapsed = !gContextMenu.isTextSelected; | |
break; | |
} | |
}, | |
ctypes: Cu.import('resource://gre/modules/ctypes.jsm', {}).ctypes, | |
read: function RS_read(text) { | |
text = this.toPhonetic(this.toKana(text)); | |
let ctypes = this.ctypes; | |
let aquesTalk2Da = ctypes.open(this.AQUES_TALK_2_DA_PATH); | |
try { | |
let playSync = aquesTalk2Da.declare('AquesTalk2Da_PlaySync', | |
ctypes.stdcall_abi, | |
ctypes.int32_t, | |
ctypes.string, | |
ctypes.int32_t, | |
ctypes.int32_t); | |
let r = playSync(this.encode(text, this.NATIVE_ENCODING), 100, 0); | |
if (r) | |
throw new Error('AquesTalk2Da_PlaySync failed: ' + r); | |
} finally { | |
aquesTalk2Da.close(); | |
} | |
}, | |
// http://www.a-quest.com/download/manual/siyo_onseikigou.pdf | |
toPhonetic: function RS_toPhonetic(text) { | |
return text.replace(/[^0-9\-,;\u3001\u3002\u3041-\u30fa\u30fc\uff1f]+/g, '/') | |
.replace(/[0-9-]+/g, '<NUM VAL=$&>'); | |
}, | |
toKana: function RS_toKana(text) { | |
let ctypes = this.ctypes; | |
let kakasi = ctypes.open(this.KAKASI_PATH); | |
try { | |
let kakasi_getopt_argv = kakasi.declare('kakasi_getopt_argv', | |
ctypes.default_abi, | |
ctypes.int32_t, | |
ctypes.int32_t, | |
ctypes.ustring); | |
let args = this.createArgs('kakasi', '-JH'); | |
let r = kakasi_getopt_argv(args.count, args.value); | |
if (r) | |
throw new Error('kakasi_getopt_argv failed: ' + r); | |
let kakasi_do = kakasi.declare('kakasi_do', | |
ctypes.default_abi, | |
ctypes.uint32_t, | |
ctypes.string); | |
let kanaPointer = kakasi_do(this.encode(text, this.NATIVE_ENCODING)); | |
let kana = this.decode(this.getCString(kanaPointer), this.NATIVE_ENCODING); | |
let kakasi_free = kakasi.declare('kakasi_free', | |
ctypes.default_abi, | |
ctypes.int32_t, | |
ctypes.uint32_t); | |
kakasi_free(kanaPointer); | |
return kana; | |
} finally { | |
kakasi.close(); | |
} | |
}, | |
createArgs: function RS_createArgs() { | |
let args = Array.map(arguments, function (argString) { | |
let ansiArg = this.encode(argString, this.NATIVE_ENCODING) + '\0'; | |
return ansiArg.replace(/[\s\S]{1,2}/g, function (s) { | |
return String.fromCharCode(s.charCodeAt(0) | | |
(s.charCodeAt(1) << 8)); | |
}); | |
}, this); | |
args.value = args.map(function (arg) { | |
let pointer = this.getPointer(arg); | |
return String.fromCharCode(pointer & 0xffff, pointer >>> 16); | |
}, this).join(''); | |
args.count = args.length; | |
return args; | |
}, | |
getPointer: function RS_getPointer(blobString) { | |
if (!blobString) return 0; | |
let ctypes = this.ctypes; | |
let crt = ctypes.open(this.CRT_PATH); | |
try { | |
let memchr = crt.declare('memchr', | |
ctypes.stdcall_abi, | |
ctypes.int32_t, | |
ctypes.ustring, | |
ctypes.int32_t, | |
ctypes.uint32_t); | |
let firstByte = blobString.charCodeAt(0) & 0xff; | |
return memchr(blobString, firstByte, 1); | |
} finally { | |
crt.close(); | |
} | |
}, | |
getCString: function RS_getCString(pointer) { | |
let ctypes = this.ctypes; | |
let crt = ctypes.open(this.CRT_PATH); | |
try { | |
let strlen = crt.declare('strlen', | |
ctypes.stdcall_abi, | |
ctypes.uint32_t, | |
ctypes.uint32_t); | |
let length = strlen(pointer); | |
let memcpy = crt.declare('memcpy', | |
ctypes.stdcall_abi, | |
ctypes.uint32_t, | |
ctypes.ustring, | |
ctypes.uint32_t, | |
ctypes.uint32_t); | |
let buffer = new Array(((length + 1) >> 1) + 1).join('\0'); | |
memcpy(buffer, pointer, length); | |
return buffer.replace(/[\s\S]/g, function (c) { | |
let n = c.charCodeAt(0); | |
return String.fromCharCode(n & 0xff, n >>> 8); | |
}).substring(0, length); | |
} finally { | |
crt.close(); | |
} | |
}, | |
encode: function RS_encode(string, encoding) { | |
let converter = Cc['@mozilla.org/intl/scriptableunicodeconverter']. | |
createInstance(Ci.nsIScriptableUnicodeConverter); | |
converter.charset = encoding; | |
return converter.ConvertFromUnicode(string); | |
}, | |
decode: function RS_decode(cString, encoding) { | |
let converter = Cc['@mozilla.org/intl/scriptableunicodeconverter']. | |
createInstance(Ci.nsIScriptableUnicodeConverter); | |
converter.charset = encoding; | |
return converter.ConvertToUnicode(cString); | |
}, | |
}).init(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment