Greasy Fork 还支持 简体中文。

toMorse

Plays selected text as morse code.

  1. // ==UserScript==
  2. // @name toMorse
  3. // @description Plays selected text as morse code.
  4. // @namespace https://greasyfork.org/en/users/11891-qon
  5. // @author Qon
  6. // @include *
  7. // @compatible firefox
  8. // @compatible chrome
  9. // @grant GM_getValue
  10. // @grant GM_setValue
  11. // @license Simple Public License 2.0 (SimPL) https://tldrlegal.com/license/simple-public-license-2.0-%28simpl%29
  12. // @version 0.0.1.20150723034148
  13. // ==/UserScript==
  14.  
  15. /*
  16. TODO
  17. Split text into smaller parts and play and request one after another.
  18. */
  19.  
  20. var settSc = {}
  21. settSc['tm-refresh'] = 0
  22. settSc['tm-stop'] = 0
  23. settSc['tm-key'] = 'm1000'
  24.  
  25. var settCw = {}
  26. settCw['cwpm'] = {def: 20, val: 20, min: 1, max: 100, label: 'Letter WPM', description: 'cwpm'}
  27. settCw['ewpm'] = {def: 20, val: 20, min: 1, max: 100, label: 'Effective WPM', description: 'ewpm'}
  28. settCw['tone'] = {def: 800, val: 800, min: 200, max: 3200, label: 'Tone frequency', description: 'tone'}
  29. settCw['vol'] = {def: 100, val: 100, min: 0, max: 100, label: 'Volume', description: 'volume'}
  30.  
  31. var currentAudio = null
  32.  
  33. function refresh() {
  34. var old = settSc['tm-refresh']['val']
  35. var nuw = GM_getValue('tm-refresh', 1)
  36. if (old != nuw) {
  37. settSc['tm-refresh'] = nuw
  38. settSc['tm-stop'] = GM_getValue('tm-stop', settSc['tm-stop'])
  39. settSc['tm-key'] = GM_getValue('tm-key', settSc['tm-key'])
  40. for (var key in settCw) {
  41. if(settCw.hasOwnProperty(key)) {
  42. settCw[key]['val'] = GM_getValue(key, settCw[key]['val'])
  43. }
  44. }
  45. }
  46. }
  47. refresh()
  48.  
  49. function signalNeedRefresh() {
  50. var o = GM_getValue('tm-refresh', 1)
  51. GM_setValue('tm-refresh', o+1)
  52. }
  53.  
  54. function evToKeystoreformat(ev) {
  55. return ev.key.toLowerCase()+(ev.ctrlKey+1-1)+(ev.shiftKey+1-1)+(ev.altKey+1-1)+(ev.metaKey+1-1)
  56. }
  57.  
  58. function dotdashToAbc(s) {
  59. var r = ''
  60. var atd = {}
  61. // atd['prosign_error']="........";
  62. atd[' ']="/";
  63. atd['a']=".-"; atd['b']="-..."; atd['c']="-.-."; atd['d']="-.."; atd['e']="."; atd['f']="..-."; atd['g']="--."; atd['h']="...."; atd['i']=".."; atd['j']=".---"; atd['k']="-.-"; atd['l']=".-.."; atd['m']="--"; atd['n']="-."; atd['o']="---"; atd['p']=".--."; atd['q']="--.-"; atd['r']=".-."; atd['s']="..."; atd['t']="-"; atd['u']="..-"; atd['v']="...-"; atd['w']=".--"; atd['x']="-..-"; atd['y']="-.--"; atd['z']="--..";
  64. atd['1']=".----"; atd['2']="..---"; atd['3']="...--"; atd['4']="....-"; atd['5']="....."; atd['6']="-...."; atd['7']="--..."; atd['8']="---.."; atd['9']="----."; atd['0']="-----"; atd['€.']=".-.-.-";
  65. atd['€,']="--..--"; atd['€?']="..--.."; atd['€!']="-.-.--"; atd['€:']="---..."; atd['€=']="-...-"; atd['€+']=".-.-."; atd['€-']="-....-";
  66. var dta = {}
  67. for(var key in atd) {
  68. if (atd.hasOwnProperty(key)) {
  69. // console.log(key, atd[key])
  70. dta[atd[key]] = key[key.length-1] // just /*= key*/ doesn't work becuse for some reason "." becomes "€." (invisible character and a dot). Same for several special chars.
  71. }
  72. }
  73.  
  74. var a = s.split(' ')
  75. for(q of a) {
  76. if (q=='') continue;
  77. var c = dta[q]
  78. if(c) {
  79. r += c
  80. } else {
  81. r = prosign_error
  82. }
  83. }
  84. console.log(r)
  85. return r
  86. }
  87.  
  88. function keypress (ev) {
  89. if (!ev) ev = window.event;
  90. if(!ev.key) {ev.key = String.fromCharCode(ev.which)}
  91. refresh()
  92. var s = evToKeystoreformat(ev)
  93. var k = settSc['tm-key']
  94. if (k == s) {
  95. var text = window.getSelection().toString()
  96. if(/[\s\.\-\/]+/.exec(text)==text){
  97. text = dotdashToAbc(text)
  98. }
  99. playTextLCWO(settCw['cwpm']['val'], settCw['ewpm']['val'], settCw['tone']['val'], settCw['vol']['val'], text)
  100. }
  101. }
  102. window.addEventListener("keydown", keypress);
  103.  
  104. function playTextLCWO(charWpm, effectiveWpm, tone, volume, str) {
  105. // var prevAudio = document.getElementById('audioLCWO')
  106. if(currentAudio) {
  107. currentAudio.pause()
  108. currentAudio = null
  109. // currentAudio.remove()
  110. }
  111. if(str=='') {
  112. return
  113. }
  114. var audio = document.createElement('audio')
  115. audio.id = 'audioLCWO'
  116. audio.class = ''+settSc['tm-stop']
  117. audio.src = 'http://cgi2.lcwo.net/cgi-bin/cw.ogg?s='+charWpm+'&e='+effectiveWpm+'&f='+tone+'&t='+str
  118. audio.addEventListener('ended', function(){/*document.getElementById('audioLCWO').remove()*/currentAudio=null});
  119. // document.body.appendChild(audio)
  120. currentAudio = audio
  121. audio.volume = volume/100
  122. audio.play()
  123. function checkStop() {
  124. refresh()
  125. // var el = document.getElementById('audioLCWO')
  126. if(currentAudio) {
  127. if(currentAudio.class != ''+settSc['tm-stop']) {
  128. currentAudio.pause()
  129. currentAudio = null
  130. // currentAudio.remove()
  131. } else {
  132. currentAudio.volume = settCw['vol']['val']/100
  133. setTimeout(checkStop, 300)
  134. }
  135. }
  136. }
  137. setTimeout(checkStop, 300)
  138. }
  139.  
  140. /*
  141. * The settings form.
  142. * Only loads on the scripts home page on greasyfork.
  143. */
  144. if (document.location == 'https://greasyfork.org/en/scripts/11117-tomorse') {
  145. var settingsdiv = document.createElement('div');
  146. settingsdiv.id = 'tomorse-settings'
  147. var h3 = document.createElement('h3')
  148. h3.innerHTML = 'Script Settings'
  149. h3.style.marginBottom = '0'
  150. h3.style.paddingBottom = '0'
  151. settingsdiv.appendChild(h3)
  152. var qontdiv = document.createElement('div');
  153. qontdiv.style.padding = '1em'
  154. qontdiv.style.margin = '0'
  155. qontdiv.style.background = '#E6FFE6'
  156. var setform = document.createElement('form');
  157.  
  158. function setting(name, variable, decription) {
  159. var span = document.createElement('span')
  160. span.innerHTML = name+': '
  161. var inpN = document.createElement('input')
  162. inpN.id = 'input-'+variable
  163. inpN.name = variable
  164. inpN.type = 'number'
  165. inpN.value = settCw[variable]['val']
  166. var inpRange = document.createElement('input')
  167. inpRange.id = 'input-range-'+variable
  168. inpRange.name = variable
  169. inpRange.type = 'range'
  170. inpRange.min = settCw[variable]['min']
  171. inpRange.max = settCw[variable]['max']
  172. inpRange.value = settCw[variable]['val']
  173. f = function(ev){
  174. var el = ev.target
  175. var inte = parseInt(el.value)
  176. GM_setValue(el.name, inte)
  177. settCw[el.name]['val'] = inte
  178. document.getElementById('input-range-'+el.name).value = inte
  179. document.getElementById('input-'+el.name).value = inte
  180. if(el.name == 'cwpm' && document.getElementById('wpm-link').checked) {
  181. document.getElementById('input-range-'+'ewpm').value = inte
  182. document.getElementById('input-'+'ewpm').value = inte
  183. GM_setValue('ewpm', inte)
  184. settCw['ewpm']['val'] = inte
  185. }
  186. signalNeedRefresh()
  187. }
  188. inpN.addEventListener('input', f)
  189. inpRange.addEventListener('input', f)
  190. setform.appendChild(span)
  191. setform.appendChild(inpN)
  192. setform.appendChild(inpRange)
  193. setform.appendChild(document.createElement('br'))
  194. }
  195.  
  196. for(var key in settCw) {
  197. if(settCw.hasOwnProperty(key)) {
  198. setting(settCw[key]['label'], key, settCw[key]['description'])
  199. }
  200. }
  201. var box = document.createElement('input')
  202. box.id = 'wpm-link'
  203. box.checked = true
  204. box.type = 'checkbox'
  205. var linkSpan = document.createElement('span')
  206. linkSpan.innerHTML = 'Copy value to "Effective WPM"'
  207. linkSpan.style.fontSize = '75%'
  208. linkSpan.style.marginLeft = '100px'
  209. setform.insertBefore(linkSpan, setform.getElementsByTagName('br')[0])
  210. setform.insertBefore(box, setform.getElementsByTagName('br')[0])
  211. // var reset = document.createElement('input')
  212. // reset.type = 'reset'
  213. // setform.appendChild(reset)
  214. var span = document.createElement('span')
  215. span.innerHTML = 'Hotkey: '
  216. var key = document.createElement('input')
  217. key.type = 'text'
  218. // key.readonly = true // doesn't work :/
  219. key.id = 'tm-key-field'
  220. function keystoreformatToString(s) {
  221. var l = s.length
  222. var r = (s[l-4]=='1'?'ctrl+':'')+(s[l-3]=='1'?'shift+':'')+(s[l-2]=='1'?'alt+':'')+(s[l-1]=='1'?'meta+':'')
  223. var e = s.slice(0, -4)
  224. if(e == 'control' || e == 'shift' || e == 'alt' || e == 'meta') {
  225. return r.slice(0,-1)
  226. }
  227. return r+e
  228. }
  229. function evToString(ev) {
  230. var r = (ev.ctrlKey?'ctrl+':'')+(ev.shiftKey?'shift+':'')+(ev.altKey?'alt+':'')+(ev.metaKey?'meta+':'')
  231. if (/[a-zA-Z\d]/.exec(ev.key)==ev.key) {
  232. if(r!='shift+' && r!='') {
  233. r += ev.key
  234. }
  235. } else if (ev.key.length==1 && !ev.ctrlKey && ev.which!=16) {
  236. r = ''
  237. } else if (ev.key.toLowerCase()=='backspace' && !ev.ctrlKey) {
  238. r += 'backspace '
  239. } else if (ev.key=='Control' || ev.key=='Shift' || ev.key == 'Alt' || ev.which==16 || ev.which==17 || ev.which==18) {
  240. r = r.slice(0, -1)
  241. } else {
  242. r += ev.key.toLowerCase()
  243. }
  244. return r
  245. }
  246. key.value = keystoreformatToString(settSc['tm-key'], false)
  247. key.addEventListener('keydown', function(ev){
  248. if (!ev) ev = window.event;
  249. if(!ev.key) {ev.key = String.fromCharCode(ev.which)}
  250. var el = ev.target
  251. GM_setValue('tm-key', evToKeystoreformat(ev))
  252. el.value = evToString(ev)
  253. signalNeedRefresh()
  254. })
  255. key.addEventListener('keyup', function (ev) {
  256. if(!(ev.key=='Control' || ev.key=='Shift' || ev.key == 'Alt')) {
  257. ev.target.blur()
  258. }
  259. })
  260. setform.appendChild(span)
  261. setform.appendChild(key)
  262. var stopSpan = document.createElement('span')
  263. stopSpan.innerHTML = 'Stop playing morse audio in all tabs: '
  264. var stop = document.createElement('input')
  265. stop.type = 'button'
  266. stop.value = 'Stop!'
  267. stop.addEventListener('click', function (ev) {
  268. GM_setValue('tm-stop', 1-GM_getValue('tm-stop', 0))
  269. signalNeedRefresh()
  270. })
  271. setform.appendChild(document.createElement('br'))
  272. setform.appendChild(stopSpan)
  273. setform.appendChild(stop)
  274. // var stopSpan = document.createElement('span')
  275. // stopSpan.innerHTML = ' (in case you can\'t find the right one because you have too many tabs!)'
  276. // stopSpan.style.fontSize = '75%'
  277. // setform.appendChild(stopSpan)
  278.  
  279. document.getElementById('script-content').insertBefore(settingsdiv, document.getElementById('share'))
  280. qontdiv.appendChild(setform)
  281. settingsdiv.appendChild(qontdiv)
  282. }