serial.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. "use strict";
  2. /**
  3. * @constructor
  4. *
  5. * @param {BusConnector} bus
  6. */
  7. function SerialAdapter(element, bus)
  8. {
  9. var serial = this;
  10. this.enabled = true;
  11. this.bus = bus;
  12. this.text = "";
  13. this.text_new_line = false;
  14. this.last_update = 0;
  15. this.bus.register("serial0-output-char", function(chr)
  16. {
  17. this.show_char(chr);
  18. }, this);
  19. this.destroy = function()
  20. {
  21. element.removeEventListener("keypress", keypress_handler, false);
  22. element.removeEventListener("keydown", keydown_handler, false);
  23. element.removeEventListener("paste", paste_handler, false);
  24. window.removeEventListener("mousedown", window_click_handler, false);
  25. };
  26. this.init = function()
  27. {
  28. this.destroy();
  29. element.style.display = "block";
  30. element.addEventListener("keypress", keypress_handler, false);
  31. element.addEventListener("keydown", keydown_handler, false);
  32. element.addEventListener("paste", paste_handler, false);
  33. window.addEventListener("mousedown", window_click_handler, false);
  34. };
  35. this.init();
  36. this.show_char = function(chr)
  37. {
  38. if(chr === "\x08")
  39. {
  40. this.text = this.text.slice(0, -1);
  41. this.update();
  42. }
  43. else if(chr === "\r")
  44. {
  45. // do nothing
  46. }
  47. else
  48. {
  49. this.text += chr;
  50. if(chr === "\n")
  51. {
  52. this.text_new_line = true;
  53. }
  54. this.update();
  55. }
  56. };
  57. this.update = function()
  58. {
  59. var now = Date.now();
  60. var delta = now - this.last_update;
  61. if(delta < 16)
  62. {
  63. if(this.update_timer === undefined)
  64. {
  65. this.update_timer = setTimeout(() => {
  66. this.update_timer = undefined;
  67. var now = Date.now();
  68. dbg_assert(now - this.last_update >= 15);
  69. this.last_update = now;
  70. this.render();
  71. }, 16 - delta);
  72. }
  73. }
  74. else
  75. {
  76. if(this.update_timer !== undefined)
  77. {
  78. clearTimeout(this.update_timer);
  79. this.update_timer = undefined;
  80. }
  81. this.last_update = now;
  82. this.render();
  83. }
  84. };
  85. this.render = function()
  86. {
  87. element.value = this.text;
  88. if(this.text_new_line)
  89. {
  90. this.text_new_line = false;
  91. element.scrollTop = 1e9;
  92. }
  93. };
  94. /**
  95. * @param {number} chr_code
  96. */
  97. this.send_char = function(chr_code)
  98. {
  99. if(serial.bus)
  100. {
  101. serial.bus.send("serial0-input", chr_code);
  102. }
  103. };
  104. function may_handle(e)
  105. {
  106. if(!serial.enabled)
  107. {
  108. return false;
  109. }
  110. // Something here?
  111. return true;
  112. }
  113. function keypress_handler(e)
  114. {
  115. if(!serial.bus)
  116. {
  117. return;
  118. }
  119. if(!may_handle(e))
  120. {
  121. return;
  122. }
  123. var chr = e.which;
  124. serial.send_char(chr);
  125. e.preventDefault();
  126. }
  127. function keydown_handler(e)
  128. {
  129. var chr = e.which;
  130. if(chr === 8)
  131. {
  132. // supress backspace
  133. serial.send_char(127);
  134. e.preventDefault();
  135. }
  136. else if(chr === 9)
  137. {
  138. // tab
  139. serial.send_char(9);
  140. e.preventDefault();
  141. }
  142. }
  143. function paste_handler(e)
  144. {
  145. if(!may_handle(e))
  146. {
  147. return;
  148. }
  149. var data = e.clipboardData.getData("text/plain");
  150. for(var i = 0; i < data.length; i++)
  151. {
  152. serial.send_char(data.charCodeAt(i));
  153. }
  154. e.preventDefault();
  155. }
  156. function window_click_handler(e)
  157. {
  158. if(e.target !== element)
  159. {
  160. element.blur();
  161. }
  162. }
  163. }
  164. /**
  165. * @constructor
  166. *
  167. * @param {BusConnector} bus
  168. */
  169. function SerialRecordingAdapter(bus)
  170. {
  171. var serial = this;
  172. this.text = "";
  173. bus.register("serial0-output-char", function(chr)
  174. {
  175. this.text += chr;
  176. }, this);
  177. }
  178. /**
  179. * @constructor
  180. * @param {BusConnector} bus
  181. */
  182. function SerialAdapterXtermJS(element, bus)
  183. {
  184. this.element = element;
  185. if(!window["Terminal"])
  186. {
  187. return;
  188. }
  189. var term = this.term = new window["Terminal"]();
  190. term["setOption"]("logLevel", "off");
  191. term.write("This is the serial console. Whatever you type or paste here will be sent to COM1");
  192. const on_data_disposable = term["onData"](function(data) {
  193. for(let i = 0; i < data.length; i++)
  194. {
  195. bus.send("serial0-input", data.charCodeAt(i));
  196. }
  197. });
  198. bus.register("serial0-output-char", function(chr)
  199. {
  200. term.write(chr);
  201. }, this);
  202. this.destroy = function() {
  203. on_data_disposable["dispose"]();
  204. term["dispose"]();
  205. };
  206. }
  207. SerialAdapterXtermJS.prototype.show = function()
  208. {
  209. this.term && this.term.open(this.element);
  210. };