\n';
+ var rstr='';
+ for (var c=0; c'+rstr+'<\/td><\/tr>\n';
+ }
+ s+='<\/table><\/td><\/tr>\n';
+ s+='<\/table><\/td><\/tr>\n';
+ s+='<\/table>\n';
+ var termOffset=2+this.conf.frameWidth;
+ if (this.globals.hasSubDivs) {
+ for (var r=0; r<\/div>\n';
+ }
+ this.globals.termStringStart='';
+ this.globals.termStringEnd='<\/td><\/tr><\/table>';
+ }
+ this.globals.writeElement(this.termDiv,s);
+ }
+ if (!rebuild) {
+ this.globals.setElementXY(this.termDiv,this.conf.x,this.conf.y);
+ this.globals.setVisible(this.termDiv,1);
+ }
+ window.status='';
+},
+
+rebuild: function() {
+ // check for bounds and array lengths
+ var rl=this.conf.rows;
+ var cl=this.conf.cols;
+ for (var r=0; r=rl) {
+ r=rl-1;
+ resetcrsr=true;
+ }
+ if (this.c>=cl) {
+ c=cl-1;
+ resetcrsr=true;
+ }
+ if (resetcrsr && this.cursoractive) this.cursorOn();
+ // and actually rebuild
+ this._makeTerm(true);
+ for (var r=0; r';
+ for (var k=tstls.length-1; k>=0; k--) {
+ var st=tstls[k];
+ if (curStyle & st) s+=tscls[st];
+ }
+ }
+ curStyle=cs;
+ for (var k=0; k>>8) & 0xff;
+ clr= (cc<16)? tclrs[cc] : 0;
+ }
+ if (curStyle & 0xff0000) {
+ var bc=((curStyle & 0xff0000)>>>16) & 0xff;
+ bgclr= (bc<16)? tclrs[bc] : 0;
+ }
+ if (clr) {
+ if (curStyle&1) {
+ s+='';
+ }
+ else if (typeof blur === 'object') {
+ s+='';
+ }
+ else if (blur) {
+ s+='';
+ }
+ else {
+ s+='';
+ }
+ }
+ }
+ s+= (tspcl[c])? tspcl[c] : String.fromCharCode(c);
+ }
+ if (curStyle>0) {
+ if (curStyle & 0xffff00) s+='';
+ for (var k=tstls.length-1; k>=0; k--) {
+ var st=tstls[k];
+ if (curStyle&st) s+=tscls[st];
+ }
+ }
+ s+=this.globals.termStringEnd;
+ this.globals.writeElement(this.termDiv+'_r'+r,s);
+},
+
+guiReady: function() {
+ var ready=true;
+ if (this.globals.guiElementsReady(this.termDiv)) {
+ for (var r=0; r='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'))? true:false;
+ },
+
+ isHexOnlyChar: function(c) {
+ return ((c>='a' && c<='f') || (c>='A' && c<='F'))? true:false;
+ },
+
+ hexToNum: {
+ '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7,
+ '8': 8, '9': 9, 'a': 10, 'b': 11, 'c': 12, 'd': 13, 'e': 14, 'f': 15,
+ 'A': 10, 'B': 11, 'C': 12, 'D': 13, 'E': 14, 'F': 15
+ },
+
+ // data for color support
+
+ webColors: [],
+ webColorCodes: [''],
+
+ colors: {
+ // ANSI bright (bold) color set
+ black: 1,
+ red: 2,
+ green: 3,
+ yellow: 4,
+ blue: 5,
+ magenta: 6,
+ cyan: 7,
+ white: 8,
+ // dark color set
+ grey: 9,
+ red2: 10,
+ green2: 11,
+ yellow2: 12,
+ blue2: 13,
+ magenta2: 14,
+ cyan2: 15,
+ // synonyms
+ red1: 2,
+ green1: 3,
+ yellow1: 4,
+ blue1: 5,
+ magenta1: 6,
+ cyan1: 7,
+ gray: 9,
+ darkred: 10,
+ darkgreen: 11,
+ darkyellow: 12,
+ darkblue: 13,
+ darkmagenta: 14,
+ darkcyan: 15,
+ // default color
+ 'default': 0,
+ clear: 0
+ },
+
+ colorCodes: [
+ '', '#000000', '#ff0000', '#00ff00', '#ffff00', '#0066ff', '#ff00ff', '#00ffff', '#ffffff',
+ '#808080', '#990000', '#009900', '#999900', '#003399', '#990099', '#009999'
+ ],
+
+ _webSwatchChars: ['0','3','6','9','c','f'],
+ _initWebColors: function() {
+ // generate long and short web color ref
+ var tg=Terminal.prototype.globals;
+ var ws=tg._webColorSwatch;
+ var wn=tg.webColors;
+ var cc=tg.webColorCodes;
+ var n=1;
+ var a, b, c, al, bl, bs, cl;
+ for (var i=0; i<6; i++) {
+ a=tg._webSwatchChars[i];
+ al=a+a;
+ for (var j=0; j<6; j++) {
+ b=tg._webSwatchChars[j];
+ bl=al+b+b;
+ bs=a+b;
+ for (var k=0; k<6; k++) {
+ c=tg._webSwatchChars[k];
+ cl=bl+c+c;
+ wn[bs+c]=wn[cl]=n;
+ cc[n]=cl;
+ n++;
+ }
+ }
+ }
+ },
+
+ webifyColor: function(s) {
+ // return nearest web color in 3 digit format
+ // (do without RegExp for compatibility)
+ var tg=Terminal.prototype.globals;
+ if (s.length==6) {
+ var c='';
+ for (var i=0; i<6; i+=2) {
+ var a=s.charAt(i);
+ var b=s.charAt(i+1);
+ if (tg.isHexChar(a) && tg.isHexChar(b)) {
+ c+=tg._webSwatchChars[Math.round(parseInt(a+b,16)/255*5)];
+ }
+ else {
+ return '';
+ }
+ }
+ return c;
+ }
+ else if (s.length==3) {
+ var c='';
+ for (var i=0; i<3; i++) {
+ var a=s.charAt(i);
+ if (tg.isHexChar(a)) {
+ c+=tg._webSwatchChars[Math.round(parseInt(a,16)/15*5)];
+ }
+ else {
+ return '';
+ }
+ }
+ return c;
+ }
+ else {
+ return '';
+ }
+ },
+
+ // public methods for color support
+
+ setColor: function(label, value) {
+ var tg=Terminal.prototype.globals;
+ if (typeof label == 'number' && label>=1 && label<=15) {
+ tg.colorCodes[label]=value;
+ }
+ else if (typeof label == 'string') {
+ label=label.toLowerCase();
+ if (label.length==1 && tg.isHexChar(label)) {
+ var n=tg.hexToNum[label];
+ if (n) tg.colorCodes[n]=value;
+ }
+ else if (typeof tg.colors[label] != 'undefined') {
+ var n=tg.colors[label];
+ if (n) tg.colorCodes[n]=value;
+ }
+ }
+ },
+
+ getColorString: function(label) {
+ var tg=Terminal.prototype.globals;
+ if (typeof label == 'number' && label>=0 && label<=15) {
+ return tg.colorCodes[label];
+ }
+ else if (typeof label == 'string') {
+ label=label.toLowerCase();
+ if (label.length==1 && tg.isHexChar(label)) {
+ return tg.colorCodes[tg.hexToNum[label]];
+ }
+ else if (typeof tg.colors[label] != 'undefined') {
+ return tg.colorCodes[tg.colors[label]];
+ }
+ }
+ return '';
+ },
+
+ getColorCode: function(label) {
+ var tg=Terminal.prototype.globals;
+ if (typeof label == 'number' && label>=0 && label<=15) {
+ return label;
+ }
+ else if (typeof label == 'string') {
+ label=label.toLowerCase();
+ if (label.length==1 && tg.isHexChar(label)) {
+ return parseInt(label,16);
+ }
+ else if (typeof tg.colors[label] != 'undefined') {
+ return tg.colors[label];
+ }
+ }
+ return 0;
+ },
+
+ // import/paste methods (methods return success)
+
+ insertText: function(text) {
+ // auto-types a given string to the active terminal
+ // returns success (false indicates a lock or no active terminal)
+ var tg=Terminal.prototype.globals;
+ var termRef = tg.activeTerm;
+ if (!termRef || termRef.closed || tg.keylock || termRef.lock || termRef.charMode || termRef.fieldMode) return false;
+ // terminal open and unlocked, so type the text
+ for (var i=0; i;
+ // (no history entry for this)
+ termRef.lineBuffer = text;
+ termRef.lastLine = '';
+ termRef.inputChar = 0;
+ termRef.handler();
+ return true;
+ },
+
+ // text related service functions
+
+ normalize: function(n,m) {
+ var s=''+n;
+ while (s.length=0) {
+ t=t.substring(0,ofs)+s2+t.substring(ofs+l1);
+ ofs=t.indexOf(s1,ofs+l2);
+ }
+ return t;
+ },
+
+
+ // config data for text wrap
+
+ wrapChars: {
+ // keys: charCode
+ // values: 1 = white space, 2 = wrap after, 3 = wrap before, 4 = conditional word break
+ 9: 1, // tab
+ 10: 1, // new line - don't change this (used internally)!!!
+ 12: 4, // form feed (use this for conditional word breaks)
+ 13: 1, // cr
+ 32: 1, // blank
+ 40: 3, // (
+ 45: 2, // dash/hyphen
+ 61: 2, // =
+ 91: 3, // [
+ 94: 3, // caret (non-printing chars)
+ 123: 3 // {
+ },
+
+
+ // keyboard methods & controls
+
+ setFocus: function(termref) {
+ Terminal.prototype.globals.activeTerm=termref;
+ Terminal.prototype.globals.clearRepeatTimer();
+ },
+
+ termKey: {
+ // codes of special keys
+ 'NUL': 0x00,
+ 'SOH': 0x01,
+ 'STX': 0x02,
+ 'ETX': 0x03,
+ 'EOT': 0x04,
+ 'ENQ': 0x05,
+ 'ACK': 0x06,
+ 'BEL': 0x07,
+ 'BS': 0x08,
+ 'BACKSPACE': 0x08,
+ 'HT': 0x09,
+ 'TAB': 0x09,
+ 'LF': 0x0A,
+ 'VT': 0x0B,
+ 'FF': 0x0C,
+ 'CR': 0x0D,
+ 'SO': 0x0E,
+ 'SI': 0x0F,
+ 'DLE': 0x10,
+ 'DC1': 0x11,
+ 'DC2': 0x12,
+ 'DC3': 0x13,
+ 'DC4': 0x14,
+ 'NAK': 0x15,
+ 'SYN': 0x16,
+ 'ETB': 0x17,
+ 'CAN': 0x18,
+ 'EM': 0x19,
+ 'SUB': 0x1A,
+ 'ESC': 0x1B,
+ 'IS4': 0x1C,
+ 'IS3': 0x1D,
+ 'IS2': 0x1E,
+ 'IS1': 0x1F,
+ 'DEL': 0x7F,
+ // other specials
+ 'EURO': 0x20AC,
+ // cursor mapping
+ 'LEFT': 0x1C,
+ 'RIGHT': 0x1D,
+ 'UP': 0x1E,
+ 'DOWN': 0x1F
+ },
+
+ // map some DOM_VK_* properties to values defined in termKey
+ termDomKeyRef: {},
+ _domKeyMappingData: {
+ 'LEFT': 'LEFT',
+ 'RIGHT': 'RIGHT',
+ 'UP': 'UP',
+ 'DOWN': 'DOWN',
+ 'BACK_SPACE': 'BS',
+ 'RETURN': 'CR',
+ 'ENTER': 'CR',
+ 'ESCAPE': 'ESC',
+ 'DELETE': 'DEL',
+ 'TAB': 'TAB'
+ },
+ _initDomKeyRef: function() {
+ var tg=Terminal.prototype.globals;
+ var m=tg._domKeyMappingData;
+ var r=tg.termDomKeyRef;
+ var k=tg.termKey;
+ for (var i in m) r['DOM_VK_'+i]=k[m[i]];
+ },
+
+ registerEvent: function(obj, eventType, handler, capture) {
+ if (obj.addEventListener) {
+ obj.addEventListener(eventType.toLowerCase(), handler, capture);
+ }
+ /*
+ else if (obj.attachEvent) {
+ obj.attachEvent('on'+eventType.toLowerCase(), handler);
+ }
+ */
+ else {
+ var et=eventType.toUpperCase();
+ if (window.Event && window.Event[et] && obj.captureEvents) obj.captureEvents(Event[et]);
+ obj['on'+eventType.toLowerCase()]=handler;
+ }
+ },
+ releaseEvent: function(obj, eventType, handler, capture) {
+ if (obj.removeEventListener) {
+ obj.removeEventListener(eventType.toLowerCase(), handler, capture);
+ }
+ /*
+ else if (obj.detachEvent) {
+ obj.detachEvent('on'+eventType.toLowerCase(), handler);
+ }
+ */
+ else {
+ var et=eventType.toUpperCase();
+ if (window.Event && window.Event[et] && obj.releaseEvents) obj.releaseEvents(Event[et]);
+ et='on'+eventType.toLowerCase();
+ if (obj[et] && obj[et]==handler) obj.et=null;
+ }
+ },
+
+ enableKeyboard: function(term) {
+ var tg=Terminal.prototype.globals;
+ if (!tg.kbdEnabled) {
+ tg.registerEvent(document, 'keypress', tg.keyHandler, true);
+ tg.registerEvent(document, 'keydown', tg.keyFix, true);
+ tg.registerEvent(document, 'keyup', tg.clearRepeatTimer, true);
+ tg.kbdEnabled=true;
+ }
+ tg.activeTerm=term;
+ },
+
+ disableKeyboard: function(term) {
+ var tg=Terminal.prototype.globals;
+ if (tg.kbdEnabled) {
+ tg.releaseEvent(document, 'keypress', tg.keyHandler, true);
+ tg.releaseEvent(document, 'keydown', tg.keyFix, true);
+ tg.releaseEvent(document, 'keyup', tg.clearRepeatTimer, true);
+ tg.kbdEnabled=false;
+ }
+ tg.activeTerm=null;
+ },
+
+ // remap some special key mappings on keydown
+
+ keyFix: function(e) {
+ var tg=Terminal.prototype.globals;
+ var term=tg.activeTerm;
+ var ch;
+ if (tg.keylock || term.lock) return true;
+ if (window.event) {
+ if (!e) e=window.event;
+ ch=e.keyCode;
+ if (e.DOM_VK_UP) {
+ for (var i in tg.termDomKeyRef) {
+ if (e[i] && ch == e[i]) {
+ tg.keyHandler({which:tg.termDomKeyRef[i],_remapped:true,_repeat:(ch==0x1B)? true:false});
+ if (e.preventDefault) e.preventDefault();
+ if (e.stopPropagation) e.stopPropagation();
+ e.cancelBubble=true;
+ return false;
+ }
+ }
+ e.cancelBubble=false;
+ return true;
+ }
+ else {
+ // no DOM support
+ var termKey=term.termKey;
+ var keyHandler=tg.keyHandler;
+ if (ch==8 && !term.isOpera) { keyHandler({which:termKey.BS,_remapped:true,_repeat:true}); }
+ else if (ch==9) { keyHandler({which:termKey.TAB,_remapped:true,_repeat: (term.printTab)? false:true}); }
+ else if (ch==27) { keyHandler({which:termKey.ESC,_remapped:true,_repeat: (term.printTab)? false:true}); }
+ else if (ch==37) { keyHandler({which:termKey.LEFT,_remapped:true,_repeat:true}); }
+ else if (ch==39) { keyHandler({which:termKey.RIGHT,_remapped:true,_repeat:true}); }
+ else if (ch==38) { keyHandler({which:termKey.UP,_remapped:true,_repeat:true}); }
+ else if (ch==40) { keyHandler({which:termKey.DOWN,_remapped:true,_repeat:true}); }
+ else if (ch==127 || ch==46) { keyHandler({which:termKey.DEL,_remapped:true,_repeat:true}); }
+ else if (ch>=57373 && ch<=57376) {
+ if (ch==57373) { keyHandler({which:termKey.UP,_remapped:true,_repeat:true}); }
+ else if (ch==57374) { keyHandler({which:termKey.DOWN,_remapped:true,_repeat:true}); }
+ else if (ch==57375) { keyHandler({which:termKey.LEFT,_remapped:true,_repeat:true}); }
+ else if (ch==57376) { keyHandler({which:termKey.RIGHT,_remapped:true,_repeat:true}); }
+ }
+ else {
+ e.cancelBubble=false;
+ return true;
+ }
+ if (e.preventDefault) e.preventDefault();
+ if (e.stopPropagation) e.stopPropagation();
+ e.cancelBubble=true;
+ return false;
+ }
+ }
+ },
+
+ clearRepeatTimer: function(e) {
+ var tg=Terminal.prototype.globals;
+ if (tg.keyRepeatTimer) {
+ clearTimeout(tg.keyRepeatTimer);
+ tg.keyRepeatTimer=null;
+ }
+ },
+
+ doKeyRepeat: function(ch) {
+ Terminal.prototype.globals.keyHandler({which:ch,_remapped:true,_repeated:true})
+ },
+
+ keyHandler: function(e) {
+ var tg=Terminal.prototype.globals;
+ var term=tg.activeTerm;
+ if (tg.keylock || term.lock || term.isMac && e && e.metaKey) return true;
+ if (window.event) {
+ if (window.event.preventDefault) window.event.preventDefault();
+ if (window.event.stopPropagation) window.event.stopPropagation();
+ }
+ else if (e) {
+ if (e.preventDefault) e.preventDefault();
+ if (e.stopPropagation) e.stopPropagation();
+ }
+ var ch;
+ var ctrl=false;
+ var shft=false;
+ var remapped=false;
+ var termKey=term.termKey;
+ var keyRepeat=0;
+ if (e) {
+ ch=e.which;
+ ctrl=((e.ctrlKey && !e.altKey) || e.modifiers==2);
+ shft=(e.shiftKey || e.modifiers==4);
+ if (e._remapped) {
+ remapped=true;
+ if (window.event) {
+ //ctrl=(ctrl || window.event.ctrlKey);
+ ctrl=(ctrl || (window.event.ctrlKey && !window.event.altKey));
+ shft=(shft || window.event.shiftKey);
+ }
+ }
+ if (e._repeated) {
+ keyRepeat=2;
+ }
+ else if (e._repeat) {
+ keyRepeat=1;
+ }
+ }
+ else if (window.event) {
+ ch=window.event.keyCode;
+ //ctrl=(window.event.ctrlKey);
+ ctrl=(window.event.ctrlKey && !window.event.altKey); // allow alt gr == ctrl alt
+ shft=(window.event.shiftKey);
+ if (window.event._repeated) {
+ keyRepeat=2;
+ }
+ else if (window.event._repeat) {
+ keyRepeat=1;
+ }
+ }
+ else {
+ return true;
+ }
+ if (ch=='' && remapped==false) {
+ // map specials
+ if (e==null) e=window.event;
+ if (e.charCode==0 && e.keyCode) {
+ if (e.DOM_VK_UP) {
+ var dkr=tg.termDomKeyRef;
+ for (var i in dkr) {
+ if (e[i] && e.keyCode == e[i]) {
+ ch=dkr[i];
+ break;
+ }
+ }
+ }
+ else {
+ // NS4
+ if (e.keyCode==28) { ch=termKey.LEFT; }
+ else if (e.keyCode==29) { ch=termKey.RIGHT; }
+ else if (e.keyCode==30) { ch=termKey.UP; }
+ else if (e.keyCode==31) { ch=termKey.DOWN; }
+ // Mozilla alike but no DOM support
+ else if (e.keyCode==37) { ch=termKey.LEFT; }
+ else if (e.keyCode==39) { ch=termKey.RIGHT; }
+ else if (e.keyCode==38) { ch=termKey.UP; }
+ else if (e.keyCode==40) { ch=termKey.DOWN; }
+ // just to have the TAB mapping here too
+ else if (e.keyCode==9) { ch=termKey.TAB; }
+ }
+ }
+ }
+ // leave on unicode private use area (might be function key etc)
+ if ((ch>=0xE000) && (ch<= 0xF8FF)) return;
+ if (keyRepeat) {
+ tg.clearRepeatTimer();
+ tg.keyRepeatTimer = window.setTimeout(
+ 'Terminal.prototype.globals.doKeyRepeat('+ch+')',
+ (keyRepeat==1)? tg.keyRepeatDelay1:tg.keyRepeatDelay2
+ );
+ }
+ // key actions
+ if (term.charMode) {
+ term.insert=false;
+ term.inputChar=ch;
+ term.lineBuffer='';
+ term.handler();
+ if (ch<=32 && window.event) window.event.cancelBubble=true;
+ return false;
+ }
+ if (!ctrl) {
+ // special keys
+ if (ch==termKey.CR) {
+ term.lock=true;
+ term.cursorOff();
+ term.insert=false;
+ if (term.rawMode) {
+ term.lineBuffer=term.lastLine;
+ }
+ else if (term.fieldMode) {
+ term.lineBuffer=term.lastLine;
+ term.exitFieldMode();
+ }
+ else {
+ term.lineBuffer=term._getLine(true);
+ if (
+ term.lineBuffer!='' &&
+ (!term.historyUnique || term.history.length==0 ||
+ term.lineBuffer!=term.history[term.history.length-1])
+ ) {
+ term.history[term.history.length]=term.lineBuffer;
+ }
+ term.histPtr=term.history.length;
+ }
+ term.lastLine='';
+ term.inputChar=0;
+ term.handler();
+ if (window.event) window.event.cancelBubble=true;
+ return false;
+ }
+ else if (term.fieldMode) {
+ if (ch==termKey.ESC) {
+ term.lineBuffer=term.lastLine='';
+ term.exitFieldMode();
+ term.lastLine='';
+ term.inputChar=0;
+ term.handler();
+ if (window.event) window.event.cancelBubble=true;
+ return false;
+ }
+ else if (ch==termKey.LEFT) {
+ if (term.fieldC>0) term.fieldC--;
+ }
+ else if (ch==termKey.RIGHT) {
+ if (term.fieldC0) {
+ term.lastLine=term.lastLine.substring(0,term.fieldC-1)+term.lastLine.substring(term.fieldC);
+ term.fieldC--;
+ }
+ }
+ else if (ch==termKey.DEL) {
+ if (term.fieldC=32) {
+ term.lastLine=term.lastLine.substring(0,term.fieldC)+String.fromCharCode(ch)+term.lastLine.substring(term.fieldC);
+ term.fieldC++;
+ }
+ term.drawField();
+ return false;
+ }
+ else if (ch==termKey.ESC && term.conf.closeOnESC) {
+ term.close();
+ if (window.event) window.event.cancelBubble=true;
+ return false;
+ }
+ if (ch<32 && term.rawMode) {
+ if (window.event) window.event.cancelBubble=true;
+ return false;
+ }
+ else {
+ if (ch==termKey.LEFT) {
+ term.cursorLeft();
+ if (window.event) window.event.cancelBubble=true;
+ return false;
+ }
+ else if (ch==termKey.RIGHT) {
+ term.cursorRight();
+ if (window.event) window.event.cancelBubble=true;
+ return false;
+ }
+ else if (ch==termKey.UP) {
+ term.cursorOff();
+ if (term.histPtr==term.history.length) term.lastLine=term._getLine();
+ term._clearLine();
+ if (term.history.length && term.histPtr>=0) {
+ if (term.histPtr>0) term.histPtr--;
+ term.type(term.history[term.histPtr]);
+ }
+ else if (term.lastLine) {
+ term.type(term.lastLine);
+ }
+ term.cursorOn();
+ if (window.event) window.event.cancelBubble=true;
+ return false;
+ }
+ else if (ch==termKey.DOWN) {
+ term.cursorOff();
+ if (term.histPtr==term.history.length) term.lastLine=term._getLine();
+ term._clearLine();
+ if (term.history.length && term.histPtr<=term.history.length) {
+ if (term.histPtr=65 && ch<=96) || ch==63) {
+ // remap canonical
+ if (ch==63) {
+ ch=31;
+ }
+ else {
+ ch-=64;
+ }
+ }
+ term.inputChar=ch;
+ term.ctrlHandler();
+ if (window.event) window.event.cancelBubble=true;
+ return false;
+ }
+ else if (ctrl || !term.isPrintable(ch,true)) {
+ if (window.event) window.event.cancelBubble=true;
+ return false;
+ }
+ else if (term.isPrintable(ch,true)) {
+ if (term.blinkTimer) clearTimeout(term.blinkTimer);
+ if (term.insert) {
+ term.cursorOff();
+ term._scrollRight(term.r,term.c);
+ }
+ term._charOut(ch);
+ term.cursorOn();
+ if (ch==32 && window.event) {
+ window.event.cancelBubble=true;
+ }
+ else if (window.opera && window.event) {
+ window.event.cancelBubble=true;
+ }
+ return false;
+ }
+ }
+ return true;
+ },
+
+
+ // gui mappings
+
+ hasSubDivs: false,
+ termStringStart: '',
+ termStringEnd: '',
+
+ termSpecials: {
+ // special HTML escapes
+ 0: ' ',
+ 1: ' ',
+ 9: ' ',
+ 32: ' ',
+ 34: '"',
+ 38: '&',
+ 60: '<',
+ 62: '>',
+ 127: '◊',
+ 0x20AC: '€'
+ },
+
+ // extensive list of max 8 styles (2^n, n<16)
+ termStyles: [1,2,4,8, 16],
+ // style markup: one letter keys, reserved keys: "p" (plain), "c" (color)
+ termStyleMarkup: {
+ 'r': 1,
+ 'u': 2,
+ 'i': 4,
+ 's': 8,
+ 'b': 16 // map "b" to 16 (italics) for ANSI mapping
+ },
+ // mappings for styles (heading HTML)
+ termStyleOpen: {
+ 1: '',
+ 2: '',
+ 4: '',
+ 8: '',
+ 16: ''
+ },
+ // mapping for styles (trailing HTML)
+ termStyleClose: {
+ 1: '<\/span>',
+ 2: '<\/u>',
+ 4: '<\/i>',
+ 8: '<\/strike>',
+ 16: ''
+ },
+
+ // method to install custom styles
+ assignStyle: function(styleCode, markup, htmlOpen, htmlClose) {
+ var tg=Terminal.prototype.globals;
+ // check params
+ if (!styleCode || isNaN(styleCode)) {
+ if (styleCode>=256) {
+ alert('termlib.js:\nCould not assign style.\n'+s+' is not a valid power of 2 between 0 and 256.');
+ return;
+ }
+ }
+ var s=styleCode&0xff;
+ var matched=false;
+ for (var i=0; i<8; i++) {
+ if ((s>>>i)&1) {
+ if (matched) {
+ alert('termlib.js:\nCould not assign style code.\n'+s+' is not a power of 2!');
+ return;
+ }
+ matched=true;
+ }
+ }
+ if (!matched) {
+ alert('termlib.js:\nCould not assign style code.\n'+s+' is not a valid power of 2 between 0 and 256.');
+ return;
+ }
+ markup=String(markup).toLowerCase();
+ if (markup=='c' || markup=='p') {
+ alert('termlib.js:\nCould not assign mark up.\n"'+markup+'" is a reserved code.');
+ return;
+ }
+ if (markup.length>1) {
+ alert('termlib.js:\nCould not assign mark up.\n"'+markup+'" is not a single letter code.');
+ return;
+ }
+ var exists=false;
+ for (var i=0; i=32) {
+ var cs=unescape("%"+high+low);
+ termString_keyref[cc]=cs;
+ termString_keycoderef[cs]=cc;
+ }
+ }
+ }
+ },
+
+ _extendMissingStringMethods: function() {
+ if (!String.fromCharCode || !String.prototype.charCodeAt) {
+ Terminal.prototype.globals._termString_makeKeyref();
+ }
+ if (!String.fromCharCode) {
+ String.fromCharCode=function(cc) {
+ return (cc!=null)? Terminal.prototype.globals.termString_keyref[cc] : '';
+ };
+ }
+ if (!String.prototype.charCodeAt) {
+ String.prototype.charCodeAt=function(n) {
+ cs=this.charAt(n);
+ return (Terminal.prototype.globals.termString_keycoderef[cs])?
+ Terminal.prototype.globals.termString_keycoderef[cs] : 0;
+ };
+ }
+ }
+
+ // end of Terminal.prototype.globals
+}
+
+// end of Terminal.prototype
+}
+
+// initialize global data
+Terminal.prototype.globals._initGlobals();
+
+// global entities for backward compatibility with termlib 1.x applications
+var TerminalDefaults = Terminal.prototype.Defaults;
+var termDefaultHandler = Terminal.prototype.defaultHandler;
+var TermGlobals = Terminal.prototype.globals;
+var termKey = Terminal.prototype.globals.termKey;
+var termDomKeyRef = Terminal.prototype.globals.termDomKeyRef;
+
+// eof
\ No newline at end of file
diff --git a/makefile b/makefile
index 9eb77a0b01..27d7643687 100644
--- a/makefile
+++ b/makefile
@@ -197,6 +197,12 @@ ifdef TARGET
ifneq ($(filter xbox%,$(triplet)),)
TARGET_OS := xbox
endif
+ ifneq ($(filter emscripten%,$(triplet)),)
+ TARGET_OS := js
+ AS = llvm-as
+ AR = emar
+ CC = emcc
+ endif
endif
ifndef TARGET_ARCH
@@ -437,6 +443,10 @@ ifneq ($(filter cygwin win32,$(TARGET_OS)),)
ALLFBLFLAGS += -t 2048
endif
+ifeq ($(TARGET_OS),js)
+ DISABLE_MT := YesPlease
+endif
+
# Pass the configuration defines on to the compiler source code
ifdef ENABLE_STANDALONE
ALLFBCFLAGS += -d ENABLE_STANDALONE
@@ -512,6 +522,11 @@ ifeq ($(TARGET_OS),dos)
RTL_OBJDIRS += $(djgpplibcobjdir)
RTL_LIBS += $(libdir)/libc.a
endif
+ifeq ($(TARGET_OS),js)
+ RTL_LIBS += $(libdir)/termlib_min.js
+ RTL_LIBS += $(libdir)/fb_rtlib.js
+ RTL_LIBS += $(libdir)/fb_shell.html
+endif
#
# Build rules
@@ -579,6 +594,15 @@ $(libdir)/fbrt0.o: $(srcdir)/rtlib/static/fbrt0.c $(LIBFB_H)
$(libdir)/fbrt0pic.o: $(srcdir)/rtlib/static/fbrt0.c $(LIBFB_H)
$(QUIET_CC)$(CC) -fPIC $(ALLCFLAGS) -c $< -o $@
+$(libdir)/termlib_min.js: $(rootdir)lib/termlib_min.js
+ cp $< $@
+
+$(libdir)/fb_rtlib.js: $(rootdir)lib/fb_rtlib.js
+ cp $< $@
+
+$(libdir)/fb_shell.html: $(rootdir)lib/fb_shell.html
+ cp $< $@
+
$(libdir)/libfb.a: $(LIBFB_C) $(LIBFB_S)
ifeq ($(TARGET_OS),dos)
# Avoid hitting the command line length limit (the libfb.a ar command line
diff --git a/src/compiler/fb.bas b/src/compiler/fb.bas
index b8657cf337..a06636c6f7 100644
--- a/src/compiler/fb.bas
+++ b/src/compiler/fb.bas
@@ -178,6 +178,15 @@ dim shared as FBTARGET targetinfo(0 to FB_COMPTARGETS-1) = _
0 or FB_TARGETOPT_UNIX _
or FB_TARGETOPT_CALLEEPOPSHIDDENPTR _
or FB_TARGETOPT_RETURNINREGS _
+ ), _
+ ( _
+ @"js", _
+ FB_DATATYPE_USHORT, _ '' wchar
+ FB_FUNCMODE_CDECL, _
+ FB_FUNCMODE_STDCALL_MS, _
+ 0 or FB_TARGETOPT_UNIX _
+ or FB_TARGETOPT_CALLEEPOPSHIDDENPTR _
+ or FB_TARGETOPT_RETURNINREGS _
) _
}
@@ -191,7 +200,8 @@ dim shared as FBCPUFAMILYINFO cpufamilyinfo(0 to FB_CPUFAMILY__COUNT-1) = _
(@"x86" , FB_DEFAULT_CPUTYPE_X86 ), _
(@"x86_64" , FB_DEFAULT_CPUTYPE_X86_64 ), _
(@"arm" , FB_DEFAULT_CPUTYPE_ARM ), _
- (@"aarch64", FB_DEFAULT_CPUTYPE_AARCH64) _
+ (@"aarch64", FB_DEFAULT_CPUTYPE_AARCH64), _
+ (@"asmjs" , FB_DEFAULT_CPUTYPE_ASMJS ) _
}
type FBCPUTYPEINFO
@@ -219,7 +229,8 @@ dim shared as FBCPUTYPEINFO cputypeinfo(0 to FB_CPUTYPE__COUNT-1) = _
( NULL , @"x86-64" , FB_CPUFAMILY_X86_64 , 64 ), _ '' FB_CPUTYPE_X86_64
( NULL , @"armv6" , FB_CPUFAMILY_ARM , 32 ), _ '' FB_CPUTYPE_ARMV6
( NULL , @"armv7-a" , FB_CPUFAMILY_ARM , 32 ), _ '' FB_CPUTYPE_ARMV7A
- ( NULL , @"aarch64" , FB_CPUFAMILY_AARCH64, 64 ) _ '' FB_CPUTYPE_AARCH64
+ ( NULL , @"aarch64" , FB_CPUFAMILY_AARCH64, 64 ), _ '' FB_CPUTYPE_AARCH64
+ ( NULL , @"asmjs" , FB_CPUFAMILY_ASMJS , 32 ) _ '' FB_CPUTYPE_ASMJS
}
''::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
diff --git a/src/compiler/fb.bi b/src/compiler/fb.bi
index 759edc290a..61a92c34b9 100644
--- a/src/compiler/fb.bi
+++ b/src/compiler/fb.bi
@@ -131,6 +131,7 @@ enum FB_CPUTYPE
FB_CPUTYPE_ARMV6
FB_CPUTYPE_ARMV7A
FB_CPUTYPE_AARCH64
+ FB_CPUTYPE_ASMJS
FB_CPUTYPE__COUNT
end enum
@@ -139,6 +140,7 @@ enum
FB_CPUFAMILY_X86_64
FB_CPUFAMILY_ARM
FB_CPUFAMILY_AARCH64
+ FB_CPUFAMILY_ASMJS
FB_CPUFAMILY__COUNT
end enum
@@ -187,6 +189,7 @@ enum FB_COMPTARGET
FB_COMPTARGET_OPENBSD
FB_COMPTARGET_DARWIN
FB_COMPTARGET_NETBSD
+ FB_COMPTARGET_JS
FB_COMPTARGETS
end enum
@@ -333,6 +336,7 @@ const FB_DEFAULT_CPUTYPE_X86 = FB_CPUTYPE_486
const FB_DEFAULT_CPUTYPE_X86_64 = FB_CPUTYPE_X86_64
const FB_DEFAULT_CPUTYPE_ARM = FB_CPUTYPE_ARMV7A
const FB_DEFAULT_CPUTYPE_AARCH64 = FB_CPUTYPE_AARCH64
+const FB_DEFAULT_CPUTYPE_ASMJS = FB_CPUTYPE_ASMJS
#ifdef __FB_ARM__
const FB_DEFAULT_CPUTYPE32 = FB_DEFAULT_CPUTYPE_ARM
diff --git a/src/compiler/fbc.bas b/src/compiler/fbc.bas
index 13ce319ddf..af7a878007 100644
--- a/src/compiler/fbc.bas
+++ b/src/compiler/fbc.bas
@@ -120,12 +120,28 @@ enum
FBCTOOL_GORC
FBCTOOL_WINDRES
FBCTOOL_CXBE
+ FBCTOOL_EMAS
+ FBCTOOL_EMAR
+ FBCTOOL_EMLD
+ FBCTOOL_EMCC
FBCTOOL__COUNT
end enum
-static shared as zstring * 8 toolnames(0 to FBCTOOL__COUNT-1) = _
+static shared as zstring * 16 toolnames(0 to FBCTOOL__COUNT-1) = _
{ _
- "as", "ar", "ld", "gcc", "llc", "dlltool", "GoRC", "windres", "cxbe" _
+ "as", _
+ "ar", _
+ "ld", _
+ "gcc", _
+ "llc", _
+ "dlltool", _
+ "GoRC", _
+ "windres", _
+ "cxbe", _
+ "llvm-as", _
+ "emar", _
+ "emcc", _
+ "emcc" _
}
declare sub fbcFindBin _
@@ -198,6 +214,8 @@ private sub hSetOutName( )
'' Note: XBox target creates an .exe first,
'' then uses cxbe to turn it into an .xbe later
fbc.outname += ".exe"
+ case FB_COMPTARGET_JS
+ fbc.outname += ".html"
end select
case FB_OUTTYPE_DYNAMICLIB
select case( fbGetOption( FB_COMPOPT_TARGET ) )
@@ -357,7 +375,11 @@ sub fbcFindBin _
#ifndef ENABLE_STANDALONE
if( hFileExists( path ) = FALSE ) then
'' c) Rely on PATH
- path = fbc.targetprefix + toolnames(tool) + FB_HOST_EXEEXT
+ if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then
+ path = fbc.targetprefix + toolnames(tool) + FB_HOST_EXEEXT
+ else
+ path = toolnames(tool)
+ end if
relying_on_system = TRUE
end if
#endif
@@ -655,6 +677,29 @@ private function hLinkFiles( ) as integer
case FB_COMPTARGET_XBOX
ldcline += " -nostdlib --file-alignment 0x20 --section-alignment 0x20 -shared"
+ case FB_COMPTARGET_JS
+ ldcline += " -O" + str( fbGetOption( FB_COMPOPT_OPTIMIZELEVEL ) )
+
+ static as zstring*32 emscripten_options(...) = _
+ { _
+ "CASE_INSENSITIVE_FS=1", _
+ "TOTAL_MEMORY=67108864", _
+ "ALLOW_MEMORY_GROWTH=1", _
+ "RETAIN_COMPILER_SETTINGS=1" _
+ }
+ '"WARN_UNALIGNED=1", _
+
+ ldcline += " -Wno-warn-absolute-paths"
+ for i as integer = 0 to ubound(emscripten_options)
+ ldcline += " -s " + emscripten_options(i)
+ next
+
+ ldcline += " --shell-file" + hFindLib("fb_shell.html")
+ ldcline += " --post-js" + hFindLib("fb_rtlib.js")
+ if( len(fbc.subsystem) = 0 ) then
+ ldcline += " --post-js" + hFindLib("termlib_min.js")
+ end if
+
end select
if (fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DOS) then
@@ -664,8 +709,10 @@ private function hLinkFiles( ) as integer
'' (needed until binutils' default DJGPP ldscripts are fixed)
ldcline += " -T """ + fbc.libpath + (FB_HOST_PATHDIV + "i386go32.x""")
else
- '' Supplementary ld script to drop the fbctinf objinfo section
- ldcline += " """ + fbc.libpath + (FB_HOST_PATHDIV + "fbextra.x""")
+ if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then
+ '' Supplementary ld script to drop the fbctinf objinfo section
+ ldcline += " """ + fbc.libpath + (FB_HOST_PATHDIV + "fbextra.x""")
+ end if
end if
select case as const fbGetOption( FB_COMPOPT_TARGET )
@@ -703,15 +750,25 @@ private function hLinkFiles( ) as integer
if( fbGetOption( FB_COMPOPT_DEBUG ) = FALSE ) then
if( fbGetOption( FB_COMPOPT_PROFILE ) = FALSE ) then
- ldcline += " -s"
+ if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then
+ ldcline += " -s"
+ end if
end if
end if
'' Add the library search paths
scope
dim as TSTRSETITEM ptr i = listGetHead(@fbc.finallibpaths.list)
+
+ dim as string L
+ if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then
+ L = " -L """
+ else
+ L = " -L"""
+ end if
+
while (i)
- ldcline += " -L """ + i->s + """"
+ ldcline += L + i->s + """"
i = listGetNext(i)
wend
end scope
@@ -792,13 +849,16 @@ private function hLinkFiles( ) as integer
end select
if( fbc.nodeflibs = FALSE ) then
- ldcline += " """ + fbc.libpath + FB_HOST_PATHDIV
- if( fbGetOption( FB_COMPOPT_PIC ) ) then
- ldcline += "fbrt0pic.o"
- else
- ldcline += "fbrt0.o"
+ '' don't add the fbrt0 if compiling for javascript, because global constructors and destructors are not supported by emscripten
+ if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then
+ ldcline += " """ + fbc.libpath + FB_HOST_PATHDIV
+ if( fbGetOption( FB_COMPOPT_PIC ) ) then
+ ldcline += "fbrt0pic.o"
+ else
+ ldcline += "fbrt0.o"
+ end if
+ ldcline += """"
end if
- ldcline += """"
end if
scope
@@ -813,7 +873,9 @@ private function hLinkFiles( ) as integer
'' All libraries are passed inside -( -) so we don't need to worry as
'' much about their order and/or listing them repeatedly.
if ( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_DARWIN ) then
- ldcline += " ""-("""
+ if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then
+ ldcline += " ""-("""
+ end if
end if
'' Add libraries passed by file name
@@ -842,8 +904,12 @@ private function hLinkFiles( ) as integer
end scope
if (fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_DARWIN) then
- '' End of lib group
- ldcline += " ""-)"""
+ if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then
+ '' End of lib group
+ ldcline += " ""-)"""
+ else
+ ldcline += " -lfb"
+ end if
end if
'' crt end
@@ -918,7 +984,12 @@ private function hLinkFiles( ) as integer
#endif
'' invoke ld
- if( fbcRunBin( "linking", FBCTOOL_LD, ldcline ) = FALSE ) then
+ var ld = FBCTOOL_LD
+ if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_JS ) then
+ ld = FBCTOOL_EMLD
+ end if
+
+ if( fbcRunBin( "linking", ld, ldcline ) = FALSE ) then
exit function
end if
@@ -2414,7 +2485,11 @@ private function hGetAsmName _
'' Based on the objfile name so it's also affected by -o
asmfile = hStripExt( *module->objfile )
- ext = @".asm"
+ if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then
+ ext = @".asm"
+ else
+ ext = @".llvm"
+ end if
if( stage = 1 ) then
select case( fbGetOption( FB_COMPOPT_BACKEND ) )
@@ -2742,10 +2817,12 @@ private function hCompileStage2Module( byval module as FBCIOFILE ptr ) as intege
ln += "-m64 "
end select
- if( fbc.cputype_is_native ) then
- ln += "-march=native "
- else
- ln += "-march=" + *fbGetGccArch( ) + " "
+ if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then
+ if( fbc.cputype_is_native ) then
+ ln += "-march=native "
+ else
+ ln += "-march=" + *fbGetGccArch( ) + " "
+ end if
end if
if( fbGetOption( FB_COMPOPT_PIC ) ) then
@@ -2753,8 +2830,13 @@ private function hCompileStage2Module( byval module as FBCIOFILE ptr ) as intege
end if
ln += "-S -nostdlib -nostdinc -Wall -Wno-unused-label " + _
- "-Wno-unused-function -Wno-unused-variable " + _
- "-Wno-unused-but-set-variable "
+ "-Wno-unused-function -Wno-unused-variable "
+
+ if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then
+ ln += "-Wno-unused-but-set-variable "
+ else
+ ln += "-Wno-warn-absolute-paths -s ASYNCIFY=1 -s RETAIN_COMPILER_SETTINGS=1 "
+ end if
'' Don't warn about non-standard main() signature
'' (we emit "ubyte **argv" instead of "char **argv")
@@ -2763,13 +2845,17 @@ private function hCompileStage2Module( byval module as FBCIOFILE ptr ) as intege
'' helps finding ir-hlc bugs
ln += "-Werror-implicit-function-declaration "
- ln += "-O" + str( fbGetOption( FB_COMPOPT_OPTIMIZELEVEL ) ) + " "
+ if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then
+ ln += "-O" + str( fbGetOption( FB_COMPOPT_OPTIMIZELEVEL ) ) + " "
+ end if
'' Do not let gcc make assumptions about pointers; FB isn't strict about it.
ln += "-fno-strict-aliasing "
'' The rtlib sets its own rounding mode, don't let gcc make assumptions.
- ln += "-frounding-math "
+ if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then
+ ln += "-frounding-math "
+ end if
'' ?
ln += "-fno-math-errno "
@@ -2833,7 +2919,11 @@ private function hCompileStage2Module( byval module as FBCIOFILE ptr ) as intege
select case( fbGetOption( FB_COMPOPT_BACKEND ) )
case FB_BACKEND_GCC
- function = fbcRunBin( "compiling C", FBCTOOL_GCC, ln )
+ var gcc = FBCTOOL_GCC
+ if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_JS ) then
+ gcc = FBCTOOL_EMCC
+ end if
+ function = fbcRunBin( "compiling C", gcc, ln )
case FB_BACKEND_LLVM
function = fbcRunBin( "compiling LLVM IR", FBCTOOL_LLC, ln )
end select
@@ -2869,14 +2959,21 @@ private function hAssembleModule( byval module as FBCIOFILE ptr ) as integer
if( fbGetOption( FB_COMPOPT_DEBUG ) = FALSE ) then
if (fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_DARWIN) then
- ln += "--strip-local-absolute "
+ if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then
+ ln += "--strip-local-absolute "
+ end if
endif
end if
ln += """" + hGetAsmName( module, 2 ) + """ "
ln += "-o """ + *module->objfile + """"
ln += fbc.extopt.gas
-
- if( fbcRunBin( "assembling", FBCTOOL_AS, ln ) = FALSE ) then
+
+ var gas = FBCTOOL_AS
+ if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_JS ) then
+ gas = FBCTOOL_EMAS
+ end if
+
+ if( fbcRunBin( "assembling", gas, ln ) = FALSE ) then
exit function
end if
@@ -3058,7 +3155,9 @@ private sub hSetDefaultLibPaths( )
'' Add gcc's private lib directory, to find libgcc
'' This is for installing into Unix-like systems, and not for
'' standalone, which has libgcc in the main lib/.
- fbcAddLibPathFor( "libgcc.a" )
+ if( fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_JS ) then
+ fbcAddLibPathFor( "libgcc.a" )
+ end if
select case( fbGetOption( FB_COMPOPT_TARGET ) )
case FB_COMPTARGET_DOS
diff --git a/src/compiler/symb-define.bas b/src/compiler/symb-define.bas
index 2554d3b03e..a5babfb31d 100644
--- a/src/compiler/symb-define.bas
+++ b/src/compiler/symb-define.bas
@@ -238,6 +238,9 @@ sub symbDefineInit _
'' Add __FB___ define
symbAddDefine( "__FB_" + ucase( *env.target.id ) + "__", NULL, 0 )
+ if( env.clopt.target = FB_COMPTARGET_JS ) then
+ symbAddDefine( @"__FB_LINUX__", NULL, 0 )
+ end if
'' add __FB_UNIX__ / __FB_PCOS__ defines, as necessary
if( env.target.options and FB_TARGETOPT_UNIX ) then
diff --git a/src/compiler/symb-struct.bas b/src/compiler/symb-struct.bas
index cc91fdb208..0822d77f77 100644
--- a/src/compiler/symb-struct.bas
+++ b/src/compiler/symb-struct.bas
@@ -73,7 +73,10 @@ function symbStructBegin _
'' Assume FIELD = 1 under -lang qb, because QB didn't do any alignment
if( fbLangIsSet( FB_LANG_QB ) ) then
if( align = 0 ) then
- align = 1
+ '' emcripten doesn't support unaligned memory access
+ if( env.clopt.target <> FB_COMPTARGET_JS ) then
+ align = 1
+ end if
end if
end if
@@ -167,7 +170,6 @@ private function hCalcPadding _
'' default?
if( align = 0 ) then
- assert( fbLangIsSet( FB_LANG_QB ) = FALSE )
align = natalign
'' packed..
else
diff --git a/src/gfxlib2/fb_gfx.h b/src/gfxlib2/fb_gfx.h
index 7a1c3f9782..aa8816f3ba 100644
--- a/src/gfxlib2/fb_gfx.h
+++ b/src/gfxlib2/fb_gfx.h
@@ -88,29 +88,6 @@
#define WINDOW_TITLE_SIZE 128
-#define EVENT_KEY_PRESS 1
-#define EVENT_KEY_RELEASE 2
-#define EVENT_KEY_REPEAT 3
-#define EVENT_MOUSE_MOVE 4
-#define EVENT_MOUSE_BUTTON_PRESS 5
-#define EVENT_MOUSE_BUTTON_RELEASE 6
-#define EVENT_MOUSE_DOUBLE_CLICK 7
-#define EVENT_MOUSE_WHEEL 8
-#define EVENT_MOUSE_ENTER 9
-#define EVENT_MOUSE_EXIT 10
-#define EVENT_WINDOW_GOT_FOCUS 11
-#define EVENT_WINDOW_LOST_FOCUS 12
-#define EVENT_WINDOW_CLOSE 13
-#define EVENT_MOUSE_HWHEEL 14
-
-#define MAX_EVENTS 128
-
-#define BUTTON_LEFT 0x1
-#define BUTTON_RIGHT 0x2
-#define BUTTON_MIDDLE 0x4
-#define BUTTON_X1 0x8
-#define BUTTON_X2 0x10
-
#define GET_WINDOW_POS 0
#define GET_WINDOW_TITLE 1
#define GET_WINDOW_HANDLE 2
@@ -158,25 +135,6 @@ typedef struct _GFX_CHAR_CELL {
unsigned fg, bg;
} GFX_CHAR_CELL;
-struct _EVENT {
- int type;
- union {
- struct { /* keyboard events */
- int scancode;
- int ascii;
- };
- struct { /* mouse events */
- int x, y;
- int dx, dy;
- };
- int button;
- int z;
- int w;
- };
-} FBPACKED;
-
-typedef struct _EVENT EVENT;
-
typedef struct FBGFX
{
int id; /**< Mode id number for contexts identification */
diff --git a/src/gfxlib2/gfx_screen.c b/src/gfxlib2/gfx_screen.c
index 265519d3c2..7047f104b5 100644
--- a/src/gfxlib2/gfx_screen.c
+++ b/src/gfxlib2/gfx_screen.c
@@ -96,8 +96,10 @@ static void release_gfx_mem(void)
static void exit_proc(void)
{
+#ifndef HOST_JS
if( __fb_gfx )
set_mode( 0, 0, 0, 0, 0, 1, 0, 0, 0, SCREEN_EXIT, 0.0, 0, 0 );
+#endif
}
/* Dummy function to ensure that the CONSOLE "update" hook for a VIEW PRINT
@@ -229,6 +231,7 @@ static int set_mode
__fb_ctx.hooks.isredirproc = fb_GfxIsRedir;
__fb_ctx.hooks.pagecopyproc = fb_GfxPageCopy;
__fb_ctx.hooks.pagesetproc = fb_GfxPageSet;
+ __fb_ctx.hooks.posteventproc = NULL;
__fb_gfx = (FBGFX *)calloc(1, sizeof(FBGFX));
}
diff --git a/src/gfxlib2/js/fb_gfx_js.h b/src/gfxlib2/js/fb_gfx_js.h
new file mode 100644
index 0000000000..1a91c07800
--- /dev/null
+++ b/src/gfxlib2/js/fb_gfx_js.h
@@ -0,0 +1,29 @@
+#include
+#include
+
+#define SCREENLIST(w, h) ((h) | (w) << 16)
+
+#define GFX_JS_FPS 60
+
+#define KEY_BUFFER_LEN 256
+
+typedef struct JS_GFXDRIVER_CTX_
+{
+ int inited;
+ int changingScreen;
+ int updated;
+ int blitting;
+
+ SDL_Surface *canvas;
+ BLITTER *blit;
+
+ int doNotCaptureKeyboard;
+} JS_GFXDRIVER_CTX;
+
+extern JS_GFXDRIVER_CTX __fb_js_ctx;
+
+
+extern void fb_js_events_init(void);
+extern void fb_js_events_exit(void);
+extern void fb_js_events_check(void);
+extern int fb_js_sdl_buttons_to_fb_buttons(int sdl_buttons);
diff --git a/src/gfxlib2/js/gfx_driver.c b/src/gfxlib2/js/gfx_driver.c
new file mode 100644
index 0000000000..355b7158ed
--- /dev/null
+++ b/src/gfxlib2/js/gfx_driver.c
@@ -0,0 +1,232 @@
+/* asmjs fbgfx driver */
+
+#include "../fb_gfx.h"
+#include "fb_gfx_js.h"
+
+JS_GFXDRIVER_CTX __fb_js_ctx =
+{
+ .inited = FALSE,
+ .changingScreen = FALSE,
+ .updated = FALSE,
+ .blitting = FALSE,
+ .canvas = NULL,
+ .doNotCaptureKeyboard = 0,
+};
+
+static void driver_exit(void);
+
+static void driver_blit()
+{
+ if(SDL_LockSurface(__fb_js_ctx.canvas) == 0)
+ {
+ __fb_js_ctx.blit(__fb_js_ctx.canvas->pixels, __fb_js_ctx.canvas->pitch);
+
+ SDL_UnlockSurface(__fb_js_ctx.canvas);
+ }
+
+ SDL_Flip(__fb_js_ctx.canvas);
+}
+
+static void driver_update(void *unused)
+{
+ if( !__fb_js_ctx.inited || __fb_gfx == NULL || __fb_gfx->framebuffer == NULL )
+ return;
+
+ int ini_time = SDL_GetTicks();
+
+ if( !__fb_js_ctx.changingScreen && !__fb_js_ctx.blitting )
+ {
+ __fb_js_ctx.blitting = TRUE;
+ driver_blit();
+ __fb_js_ctx.blitting = FALSE;
+
+ __fb_js_ctx.updated = TRUE;
+
+ fb_js_events_check( );
+ }
+
+ int delay = (1000/GFX_JS_FPS) - (SDL_GetTicks() - ini_time);
+
+ emscripten_async_call(driver_update, NULL, MAX( delay, 1 ) );
+}
+
+
+static int driver_init(char *title, int w, int h, int depth_arg, int refresh_rate, int flags)
+{
+ if( w == 0 || h == 0 || depth_arg == 0 )
+ return 0;
+
+ __fb_js_ctx.changingScreen = TRUE;
+
+ if( !__fb_js_ctx.inited )
+ {
+ fb_js_events_init();
+ SDL_Init(SDL_INIT_VIDEO);
+ }
+
+ if( __fb_js_ctx.canvas != NULL )
+ SDL_FreeSurface(__fb_js_ctx.canvas);
+
+ __fb_js_ctx.canvas = SDL_SetVideoMode(w, h, 32, SDL_HWSURFACE);
+
+ __fb_js_ctx.blit = fb_hGetBlitter(__fb_js_ctx.canvas->format->BitsPerPixel, TRUE);
+
+ __fb_js_ctx.changingScreen = FALSE;
+ __fb_js_ctx.blitting = FALSE;
+
+ int was_inited = __fb_js_ctx.inited;
+ __fb_js_ctx.inited = TRUE;
+
+ if( !was_inited )
+ {
+ __fb_js_ctx.updated = 0;
+ emscripten_async_call(driver_update, NULL, 1000/GFX_JS_FPS);
+ }
+
+ return 0;
+}
+
+static void driver_exit(void)
+{
+ if( __fb_js_ctx.inited )
+ {
+ __fb_js_ctx.inited = FALSE;
+
+ if( !__fb_js_ctx.updated )
+ driver_blit();
+
+ if( __fb_js_ctx.canvas != NULL )
+ {
+ SDL_FreeSurface(__fb_js_ctx.canvas);
+ __fb_js_ctx.canvas = NULL;
+ }
+
+ fb_js_events_exit();
+
+ SDL_Quit();
+ }
+}
+
+static void driver_lock(void)
+{
+ /* !!!WRITEME!!! */
+}
+
+static void driver_unlock(void)
+{
+ /* !!!WRITEME!!! */
+}
+
+static void driver_wait_vsync(void)
+{
+ /* !!!WRITEME!!! */
+}
+
+int fb_js_sdl_buttons_to_fb_buttons(int sdl_buttons)
+{
+ int fb_buttons = 0;
+
+ if( sdl_buttons & SDL_BUTTON_LMASK)
+ fb_buttons |= BUTTON_LEFT;
+ if( sdl_buttons & SDL_BUTTON_MMASK)
+ fb_buttons |= BUTTON_MIDDLE;
+ if( sdl_buttons & SDL_BUTTON_RMASK)
+ fb_buttons |= BUTTON_RIGHT;
+ if( sdl_buttons & SDL_BUTTON_X1MASK)
+ fb_buttons |= BUTTON_X1;
+ if( sdl_buttons & SDL_BUTTON_X2MASK)
+ fb_buttons |= BUTTON_X2;
+
+ return fb_buttons;
+}
+
+static int driver_get_mouse(int *x, int *y, int *z, int *buttons, int *clip)
+{
+ SDL_PumpEvents();
+
+ *buttons = fb_js_sdl_buttons_to_fb_buttons(SDL_GetMouseState(x, y));
+
+ *z = 0;
+ *clip = 0;
+
+ return 0;
+}
+
+static void driver_set_mouse(int x, int y, int cursor, int clip)
+{
+ //SDL_WarpMouseInWindow(NULL, x, y);
+}
+
+static int modes[] = {
+ SCREENLIST(640, 480),
+ SCREENLIST(512, 512),
+ SCREENLIST(320, 240),
+ SCREENLIST(320, 200),
+ SCREENLIST(320, 100),
+ SCREENLIST(256, 256),
+ SCREENLIST(160, 120),
+ SCREENLIST(80, 80)
+};
+
+static int *driver_fetch_modes(int depth, int *size)
+{
+ *size = sizeof(modes) / sizeof(int);
+ return memcpy((void*)malloc(sizeof(modes)), modes, sizeof(modes));
+}
+
+static void driver_poll_events(void)
+{
+ fb_js_events_check( );
+}
+
+static void driver_set_window_title(char *title)
+{
+ SDL_WM_SetCaption(title, NULL);
+}
+
+static const GFXDRIVER fb_gfxDriverJS =
+{
+ "asmjs", /* char *name; */
+ driver_init, /* int (*init)(char *title, int w, int h, int depth, int refresh_rate, int flags); */
+ driver_exit, /* void (*exit)(void); */
+ driver_lock, /* void (*lock)(void); */
+ driver_unlock, /* void (*unlock)(void); */
+ NULL, /* void (*set_palette)(int index, int r, int g, int b); */
+ driver_wait_vsync, /* void (*wait_vsync)(void); */
+ driver_get_mouse, /* int (*get_mouse)(int *x, int *y, int *z, int *buttons, int *clip); */
+ driver_set_mouse, /* void (*set_mouse)(int x, int y, int cursor, int clip); */
+ driver_set_window_title, /* void (*set_window_title)(char *title); */
+ NULL, /* int (*set_window_pos)(int x, int y); */
+ driver_fetch_modes, /* int *(*fetch_modes)(int depth, int *size); */
+ NULL, /* void (*flip)(void); */
+ driver_poll_events /* void (*poll_events)(void); */
+};
+
+const GFXDRIVER *__fb_gfx_drivers_list[] = {
+ &fb_gfxDriverJS,
+ NULL
+};
+
+void fb_hScreenInfo(ssize_t *width, ssize_t *height, ssize_t *depth, ssize_t *refresh)
+{
+ *width = 512;
+ *height = 512;
+ *depth = 32;
+ *refresh = GFX_JS_FPS;
+}
+
+FBCALL int fb_GfxGetJoystick(int id, ssize_t *buttons, float *a1, float *a2, float *a3, float *a4, float *a5, float *a6, float *a7, float *a8)
+{
+ FB_GRAPHICS_LOCK( );
+
+ *buttons = -1;
+ *a1 = *a2 = *a3 = *a4 = *a5 = *a6 = *a7 = *a8 = -1000.0f;
+
+ if ((id < 0) || (id >= 4)) {
+ FB_GRAPHICS_UNLOCK( );
+ return fb_ErrorSetNum(FB_RTERROR_ILLEGALFUNCTIONCALL);
+ }
+
+ FB_GRAPHICS_UNLOCK( );
+ return fb_ErrorSetNum( FB_RTERROR_OK );
+}
diff --git a/src/gfxlib2/js/gfx_events.c b/src/gfxlib2/js/gfx_events.c
new file mode 100644
index 0000000000..45300d6b03
--- /dev/null
+++ b/src/gfxlib2/js/gfx_events.c
@@ -0,0 +1,90 @@
+#include "../fb_gfx.h"
+#include "fb_gfx_js.h"
+
+static int sleep_called = 0;
+
+void fb_js_events_check(void)
+{
+ SDL_PumpEvents();
+
+ SDL_Event event;
+
+ while( SDL_PollEvent(&event) )
+ {
+ switch( event.type )
+ {
+ case SDL_MOUSEMOTION:
+ {
+ EVENT e =
+ {
+ .type = EVENT_MOUSE_MOVE,
+ .x = event.motion.x,
+ .y = event.motion.y,
+ .dx = event.motion.xrel,
+ .dy = event.motion.yrel,
+ };
+
+ fb_hPostEvent(&e);
+ break;
+ }
+
+ case SDL_MOUSEBUTTONDOWN:
+ {
+ EVENT e =
+ {
+ .type = EVENT_MOUSE_BUTTON_PRESS,
+ .button = fb_js_sdl_buttons_to_fb_buttons(event.button.button),
+ };
+
+ fb_hPostEvent(&e);
+ break;
+ }
+
+ case SDL_MOUSEBUTTONUP:
+ {
+ EVENT e =
+ {
+ .type = EVENT_MOUSE_BUTTON_RELEASE,
+ .button = fb_js_sdl_buttons_to_fb_buttons(event.button.button),
+ };
+
+ fb_hPostEvent(&e);
+ break;
+ }
+ }
+ }
+}
+
+static void fb_js_sleep(int msecs)
+{
+ if( !sleep_called )
+ {
+ sleep_called = 1;
+ emscripten_log(EM_LOG_WARN, "Warning: Call to SLEEP() ignored. It should not be used in Javascript");
+ }
+}
+
+void fb_js_events_init(void)
+{
+ __fb_ctx.hooks.sleepproc = fb_js_sleep;
+
+ // we can't use SDL's key events because CAPSLOCK isn't handled by emscripten and the printable chars are always lowercase in SDL
+ __fb_ctx.hooks.inkeyproc = NULL;
+ __fb_ctx.hooks.getkeyproc = NULL;
+ __fb_ctx.hooks.keyhitproc = NULL;
+ __fb_ctx.hooks.multikeyproc = NULL;
+ __fb_ctx.hooks.posteventproc = fb_hPostEvent;
+
+ // don't let SDL capture the keyboard
+ __fb_js_ctx.doNotCaptureKeyboard = emscripten_run_script_int("Module['doNotCaptureKeyboard']? 1: 0;");
+ if(!__fb_js_ctx.doNotCaptureKeyboard)
+ emscripten_run_script("Module['doNotCaptureKeyboard']=1;");
+
+ return;
+}
+
+void fb_js_events_exit(void)
+{
+ if(!__fb_js_ctx.doNotCaptureKeyboard)
+ emscripten_run_script("Module['doNotCaptureKeyboard']=null;");
+}
diff --git a/src/rtlib/con_lineinp.c b/src/rtlib/con_lineinp.c
index d802094825..491328a232 100644
--- a/src/rtlib/con_lineinp.c
+++ b/src/rtlib/con_lineinp.c
@@ -101,7 +101,7 @@ int fb_ConsoleLineInput
{
/* create temporary string */
- FBSTRING str_result = { 0 };
+ FBSTRING str_result = { .data = NULL, .len = 0, .size = 0 };
res = fb_DevFileReadLineDumb( stdin, &str_result, hWrapper );
diff --git a/src/rtlib/fb.h b/src/rtlib/fb.h
index eff681088c..811046bdf5 100644
--- a/src/rtlib/fb.h
+++ b/src/rtlib/fb.h
@@ -322,125 +322,11 @@ void fb_hListDynElemRemove ( FB_LIST *list, FB_LISTELEM *elem )
#include "fb_printer.h"
#include "fb_datetime.h"
#include "fb_thread.h"
+#include "fb_event.h"
#include "fb_hook.h"
#include "fb_oop.h"
#include "fb_legacy.h"
-/* DOS keyboard scancodes */
-#define SC_ESCAPE 0x01
-#define SC_1 0x02
-#define SC_2 0x03
-#define SC_3 0x04
-#define SC_4 0x05
-#define SC_5 0x06
-#define SC_6 0x07
-#define SC_7 0x08
-#define SC_8 0x09
-#define SC_9 0x0A
-#define SC_0 0x0B
-#define SC_MINUS 0x0C
-#define SC_EQUALS 0x0D
-#define SC_BACKSPACE 0x0E
-#define SC_TAB 0x0F
-#define SC_Q 0x10
-#define SC_W 0x11
-#define SC_E 0x12
-#define SC_R 0x13
-#define SC_T 0x14
-#define SC_Y 0x15
-#define SC_U 0x16
-#define SC_I 0x17
-#define SC_O 0x18
-#define SC_P 0x19
-#define SC_LEFTBRACKET 0x1A
-#define SC_RIGHTBRACKET 0x1B
-#define SC_ENTER 0x1C
-#define SC_CONTROL 0x1D
-#define SC_A 0x1E
-#define SC_S 0x1F
-#define SC_D 0x20
-#define SC_F 0x21
-#define SC_G 0x22
-#define SC_H 0x23
-#define SC_J 0x24
-#define SC_K 0x25
-#define SC_L 0x26
-#define SC_SEMICOLON 0x27
-#define SC_QUOTE 0x28
-#define SC_TILDE 0x29
-#define SC_LSHIFT 0x2A
-#define SC_BACKSLASH 0x2B
-#define SC_Z 0x2C
-#define SC_X 0x2D
-#define SC_C 0x2E
-#define SC_V 0x2F
-#define SC_B 0x30
-#define SC_N 0x31
-#define SC_M 0x32
-#define SC_COMMA 0x33
-#define SC_PERIOD 0x34
-#define SC_SLASH 0x35
-#define SC_RSHIFT 0x36
-#define SC_MULTIPLY 0x37
-#define SC_ALT 0x38
-#define SC_SPACE 0x39
-#define SC_CAPSLOCK 0x3A
-#define SC_F1 0x3B
-#define SC_F2 0x3C
-#define SC_F3 0x3D
-#define SC_F4 0x3E
-#define SC_F5 0x3F
-#define SC_F6 0x40
-#define SC_F7 0x41
-#define SC_F8 0x42
-#define SC_F9 0x43
-#define SC_F10 0x44
-#define SC_NUMLOCK 0x45
-#define SC_SCROLLLOCK 0x46
-#define SC_HOME 0x47
-#define SC_UP 0x48
-#define SC_PAGEUP 0x49
-#define SC_LEFT 0x4B
-#define SC_CLEAR 0x4C
-#define SC_RIGHT 0x4D
-#define SC_PLUS 0x4E
-#define SC_END 0x4F
-#define SC_DOWN 0x50
-#define SC_PAGEDOWN 0x51
-#define SC_INSERT 0x52
-#define SC_DELETE 0x53
-#define SC_F11 0x57
-#define SC_F12 0x58
-#define SC_LWIN 0x5B
-#define SC_RWIN 0x5C
-#define SC_MENU 0x5D
-#define SC_ALTGR 0x64
-
-#define KEY_BACKSPACE 8
-#define KEY_TAB '\t'
-#define KEY_F1 FB_MAKE_EXT_KEY( ';' )
-#define KEY_F2 FB_MAKE_EXT_KEY( '<' )
-#define KEY_F3 FB_MAKE_EXT_KEY( '=' )
-#define KEY_F4 FB_MAKE_EXT_KEY( '>' )
-#define KEY_F5 FB_MAKE_EXT_KEY( '?' )
-#define KEY_F6 FB_MAKE_EXT_KEY( '@' )
-#define KEY_F7 FB_MAKE_EXT_KEY( 'A' )
-#define KEY_F8 FB_MAKE_EXT_KEY( 'B' )
-#define KEY_F9 FB_MAKE_EXT_KEY( 'C' )
-#define KEY_F10 FB_MAKE_EXT_KEY( 'D' )
-#define KEY_HOME FB_MAKE_EXT_KEY( 'G' )
-#define KEY_UP FB_MAKE_EXT_KEY( 'H' )
-#define KEY_PAGE_UP FB_MAKE_EXT_KEY( 'I' )
-#define KEY_LEFT FB_MAKE_EXT_KEY( 'K' )
-#define KEY_CLEAR FB_MAKE_EXT_KEY( 'L' )
-#define KEY_RIGHT FB_MAKE_EXT_KEY( 'M' )
-#define KEY_END FB_MAKE_EXT_KEY( 'O' )
-#define KEY_DOWN FB_MAKE_EXT_KEY( 'P' )
-#define KEY_PAGE_DOWN FB_MAKE_EXT_KEY( 'Q' )
-#define KEY_INS FB_MAKE_EXT_KEY( 'R' )
-#define KEY_DEL FB_MAKE_EXT_KEY( 'S' )
-#define KEY_QUIT FB_MAKE_EXT_KEY( 'k' )
-
FBSTRING *fb_hMakeInkeyStr( int ch );
int fb_hScancodeToExtendedKey( int scancode );
diff --git a/src/rtlib/fb_config.h b/src/rtlib/fb_config.h
index 3be8f0c7c9..74f7ef7340 100644
--- a/src/rtlib/fb_config.h
+++ b/src/rtlib/fb_config.h
@@ -35,6 +35,9 @@
#elif (defined sun || defined __sun) && defined __SVR4
#define HOST_SOLARIS
#define HOST_UNIX
+#elif defined __EMSCRIPTEN__
+ #define HOST_JS
+ #define HOST_UNIX
#else
#error "Couldn't identify target system!"
#endif
diff --git a/src/rtlib/fb_event.h b/src/rtlib/fb_event.h
new file mode 100644
index 0000000000..2b182a3dda
--- /dev/null
+++ b/src/rtlib/fb_event.h
@@ -0,0 +1,159 @@
+struct _EVENT {
+ int type;
+ union {
+ struct { /* keyboard events */
+ int scancode;
+ int ascii;
+ };
+ struct { /* mouse events */
+ int x, y;
+ int dx, dy;
+ };
+ int button;
+ int z;
+ int w;
+ };
+} FBPACKED;
+
+typedef struct _EVENT EVENT;
+
+#define EVENT_KEY_PRESS 1
+#define EVENT_KEY_RELEASE 2
+#define EVENT_KEY_REPEAT 3
+#define EVENT_MOUSE_MOVE 4
+#define EVENT_MOUSE_BUTTON_PRESS 5
+#define EVENT_MOUSE_BUTTON_RELEASE 6
+#define EVENT_MOUSE_DOUBLE_CLICK 7
+#define EVENT_MOUSE_WHEEL 8
+#define EVENT_MOUSE_ENTER 9
+#define EVENT_MOUSE_EXIT 10
+#define EVENT_WINDOW_GOT_FOCUS 11
+#define EVENT_WINDOW_LOST_FOCUS 12
+#define EVENT_WINDOW_CLOSE 13
+#define EVENT_MOUSE_HWHEEL 14
+
+#define MAX_EVENTS 128
+
+#define BUTTON_LEFT 0x1
+#define BUTTON_RIGHT 0x2
+#define BUTTON_MIDDLE 0x4
+#define BUTTON_X1 0x8
+#define BUTTON_X2 0x10
+
+/* DOS keyboard scancodes */
+#define SC_ESCAPE 0x01
+#define SC_1 0x02
+#define SC_2 0x03
+#define SC_3 0x04
+#define SC_4 0x05
+#define SC_5 0x06
+#define SC_6 0x07
+#define SC_7 0x08
+#define SC_8 0x09
+#define SC_9 0x0A
+#define SC_0 0x0B
+#define SC_MINUS 0x0C
+#define SC_EQUALS 0x0D
+#define SC_BACKSPACE 0x0E
+#define SC_TAB 0x0F
+#define SC_Q 0x10
+#define SC_W 0x11
+#define SC_E 0x12
+#define SC_R 0x13
+#define SC_T 0x14
+#define SC_Y 0x15
+#define SC_U 0x16
+#define SC_I 0x17
+#define SC_O 0x18
+#define SC_P 0x19
+#define SC_LEFTBRACKET 0x1A
+#define SC_RIGHTBRACKET 0x1B
+#define SC_ENTER 0x1C
+#define SC_CONTROL 0x1D
+#define SC_A 0x1E
+#define SC_S 0x1F
+#define SC_D 0x20
+#define SC_F 0x21
+#define SC_G 0x22
+#define SC_H 0x23
+#define SC_J 0x24
+#define SC_K 0x25
+#define SC_L 0x26
+#define SC_SEMICOLON 0x27
+#define SC_QUOTE 0x28
+#define SC_TILDE 0x29
+#define SC_LSHIFT 0x2A
+#define SC_BACKSLASH 0x2B
+#define SC_Z 0x2C
+#define SC_X 0x2D
+#define SC_C 0x2E
+#define SC_V 0x2F
+#define SC_B 0x30
+#define SC_N 0x31
+#define SC_M 0x32
+#define SC_COMMA 0x33
+#define SC_PERIOD 0x34
+#define SC_SLASH 0x35
+#define SC_RSHIFT 0x36
+#define SC_MULTIPLY 0x37
+#define SC_ALT 0x38
+#define SC_SPACE 0x39
+#define SC_CAPSLOCK 0x3A
+#define SC_F1 0x3B
+#define SC_F2 0x3C
+#define SC_F3 0x3D
+#define SC_F4 0x3E
+#define SC_F5 0x3F
+#define SC_F6 0x40
+#define SC_F7 0x41
+#define SC_F8 0x42
+#define SC_F9 0x43
+#define SC_F10 0x44
+#define SC_NUMLOCK 0x45
+#define SC_SCROLLLOCK 0x46
+#define SC_HOME 0x47
+#define SC_UP 0x48
+#define SC_PAGEUP 0x49
+#define SC_LEFT 0x4B
+#define SC_CLEAR 0x4C
+#define SC_RIGHT 0x4D
+#define SC_PLUS 0x4E
+#define SC_END 0x4F
+#define SC_DOWN 0x50
+#define SC_PAGEDOWN 0x51
+#define SC_INSERT 0x52
+#define SC_DELETE 0x53
+#define SC_F11 0x57
+#define SC_F12 0x58
+#define SC_LWIN 0x5B
+#define SC_RWIN 0x5C
+#define SC_MENU 0x5D
+#define SC_ALTGR 0x64
+
+#define KEY_BACKSPACE 8
+#define KEY_TAB '\t'
+#define KEY_F1 FB_MAKE_EXT_KEY( ';' )
+#define KEY_F2 FB_MAKE_EXT_KEY( '<' )
+#define KEY_F3 FB_MAKE_EXT_KEY( '=' )
+#define KEY_F4 FB_MAKE_EXT_KEY( '>' )
+#define KEY_F5 FB_MAKE_EXT_KEY( '?' )
+#define KEY_F6 FB_MAKE_EXT_KEY( '@' )
+#define KEY_F7 FB_MAKE_EXT_KEY( 'A' )
+#define KEY_F8 FB_MAKE_EXT_KEY( 'B' )
+#define KEY_F9 FB_MAKE_EXT_KEY( 'C' )
+#define KEY_F10 FB_MAKE_EXT_KEY( 'D' )
+#define KEY_HOME FB_MAKE_EXT_KEY( 'G' )
+#define KEY_UP FB_MAKE_EXT_KEY( 'H' )
+#define KEY_PAGE_UP FB_MAKE_EXT_KEY( 'I' )
+#define KEY_LEFT FB_MAKE_EXT_KEY( 'K' )
+#define KEY_CLEAR FB_MAKE_EXT_KEY( 'L' )
+#define KEY_RIGHT FB_MAKE_EXT_KEY( 'M' )
+#define KEY_END FB_MAKE_EXT_KEY( 'O' )
+#define KEY_DOWN FB_MAKE_EXT_KEY( 'P' )
+#define KEY_PAGE_DOWN FB_MAKE_EXT_KEY( 'Q' )
+#define KEY_INS FB_MAKE_EXT_KEY( 'R' )
+#define KEY_DEL FB_MAKE_EXT_KEY( 'S' )
+#define KEY_QUIT FB_MAKE_EXT_KEY( 'k' )
+
+#define QB_EXTK(x)(((unsigned short)(x))<<8|0xff)
+
diff --git a/src/rtlib/fb_hook.h b/src/rtlib/fb_hook.h
index 9b4ef32948..684beef7bb 100644
--- a/src/rtlib/fb_hook.h
+++ b/src/rtlib/fb_hook.h
@@ -88,6 +88,8 @@ typedef int (*FB_PAGECOPYPROC) ( int src, int dst );
FBCALL int fb_PageSet ( int active, int visible );
typedef int (*FB_PAGESETPROC) ( int active, int visible );
+typedef void (*FB_POSTEVENTPROC) (EVENT *e);
+
typedef struct FB_HOOKSTB {
FB_INKEYPROC inkeyproc;
FB_GETKEYPROC getkeyproc;
@@ -116,4 +118,5 @@ typedef struct FB_HOOKSTB {
FB_ISREDIRPROC isredirproc;
FB_PAGECOPYPROC pagecopyproc;
FB_PAGESETPROC pagesetproc;
+ FB_POSTEVENTPROC posteventproc;
} FB_HOOKSTB;
diff --git a/src/rtlib/init.c b/src/rtlib/init.c
index 6866fd792b..75706df255 100644
--- a/src/rtlib/init.c
+++ b/src/rtlib/init.c
@@ -106,6 +106,11 @@ FBCALL void fb_Init( int argc, char **argv, int lang )
__fb_ctx.argc = argc;
__fb_ctx.argv = argv;
__fb_ctx.lang = lang;
+
+#ifdef HOST_JS
+ // global constructors and destructors are not supported by emscripten
+ fb_hRtInit();
+#endif // HOST_JS
}
/* called by FB program,
@@ -114,5 +119,11 @@ FBCALL void fb_End( int errlevel )
{
if( __fb_ctx.exit_gfxlib2 )
__fb_ctx.exit_gfxlib2( );
+
+#ifdef HOST_JS
+ // global constructors and destructors are not supported by emscripten
+ fb_hRtExit();
+#endif // HOST_JS
+
exit( errlevel );
}
diff --git a/src/rtlib/js/drv_intl_get.c b/src/rtlib/js/drv_intl_get.c
new file mode 100644
index 0000000000..64202e6693
--- /dev/null
+++ b/src/rtlib/js/drv_intl_get.c
@@ -0,0 +1,9 @@
+/* get i18n data */
+
+#include "../fb.h"
+
+const char *fb_DrvIntlGet( eFbIntlIndex Index )
+{
+ /* No I18N information available */
+ return NULL;
+}
diff --git a/src/rtlib/js/drv_intl_getdateformat.c b/src/rtlib/js/drv_intl_getdateformat.c
new file mode 100644
index 0000000000..1cdd24ca6e
--- /dev/null
+++ b/src/rtlib/js/drv_intl_getdateformat.c
@@ -0,0 +1,9 @@
+/* get localized short DATE format */
+
+#include "../fb.h"
+
+int fb_DrvIntlGetDateFormat( char *buffer, size_t len )
+{
+ /* No localized date format available! */
+ return FALSE;
+}
diff --git a/src/rtlib/js/drv_intl_getmonthname.c b/src/rtlib/js/drv_intl_getmonthname.c
new file mode 100644
index 0000000000..fe5d71e21a
--- /dev/null
+++ b/src/rtlib/js/drv_intl_getmonthname.c
@@ -0,0 +1,9 @@
+/* get localized month name */
+
+#include "../fb.h"
+
+FBSTRING *fb_DrvIntlGetMonthName( int month, int short_names )
+{
+ /* No localized month name available */
+ return NULL;
+}
diff --git a/src/rtlib/js/drv_intl_gettimeformat.c b/src/rtlib/js/drv_intl_gettimeformat.c
new file mode 100644
index 0000000000..efb7330a01
--- /dev/null
+++ b/src/rtlib/js/drv_intl_gettimeformat.c
@@ -0,0 +1,9 @@
+/* get localized short TIME format */
+
+#include "../fb.h"
+
+int fb_DrvIntlGetTimeFormat( char *buffer, size_t len )
+{
+ /* No localized time format available! */
+ return FALSE;
+}
diff --git a/src/rtlib/js/drv_intl_getweekdayname.c b/src/rtlib/js/drv_intl_getweekdayname.c
new file mode 100644
index 0000000000..12880dfd84
--- /dev/null
+++ b/src/rtlib/js/drv_intl_getweekdayname.c
@@ -0,0 +1,9 @@
+/* get localized weekday name */
+
+#include "../fb.h"
+
+FBSTRING *fb_DrvIntlGetWeekdayName( int weekday, int short_names )
+{
+ /* No localized weekday name available */
+ return NULL;
+}
diff --git a/src/rtlib/js/fb_js.h b/src/rtlib/js/fb_js.h
new file mode 100644
index 0000000000..0fe7ab5c41
--- /dev/null
+++ b/src/rtlib/js/fb_js.h
@@ -0,0 +1,17 @@
+#define FBCALL __stdcall
+
+/* newline for console/file I/O */
+#define FB_NEWLINE "\r\n"
+#define FB_NEWLINE_WSTR _LC("\r\n")
+
+/* newline for printer I/O */
+#define FB_BINARY_NEWLINE "\r\n"
+#define FB_BINARY_NEWLINE_WSTR _LC("\r\n")
+#define FB_LL_FMTMOD "ll"
+#define FB_CONSOLE_MAXPAGES 1
+#define FB_DYLIB HANDLE
+
+typedef long fb_off_t;
+#define fseeko(stream, offset, whence) fseek(stream, offset, whence)
+#define ftello(stream) ftell(stream)
+
diff --git a/src/rtlib/js/fb_private_console.h b/src/rtlib/js/fb_private_console.h
new file mode 100644
index 0000000000..22c702b893
--- /dev/null
+++ b/src/rtlib/js/fb_private_console.h
@@ -0,0 +1,48 @@
+#include
+#include
+
+#define KEY_BUFFER_LEN 256
+
+#define FB_COLOR_BLACK (0)
+#define FB_COLOR_BLUE (1)
+#define FB_COLOR_GREEN (2)
+#define FB_COLOR_CYAN (3)
+#define FB_COLOR_RED (4)
+#define FB_COLOR_MAGENTA (5)
+#define FB_COLOR_BROWN (6)
+#define FB_COLOR_WHITE (7)
+#define FB_COLOR_GREY (8)
+#define FB_COLOR_LBLUE (9)
+#define FB_COLOR_LGREEN (10)
+#define FB_COLOR_LCYAN (11)
+#define FB_COLOR_LRED (12)
+#define FB_COLOR_LMAGENTA (13)
+#define FB_COLOR_YELLOW (14)
+#define FB_COLOR_BWHITE (15)
+
+typedef struct _FB_CONSOLE_MOUSE {
+ int x;
+ int y;
+ int z;
+ int dx;
+ int dy;
+ int button;
+} FB_CONSOLE_MOUSE;
+
+typedef struct _FB_CONSOLE_CTX {
+ int active, visible;
+ int w, h;
+ unsigned long key_buffer[KEY_BUFFER_LEN];
+ int key_head;
+ int key_tail;
+ unsigned char multikey[128];
+ FB_CONSOLE_MOUSE mouse;
+ const char *color_remap;
+} FB_CONSOLE_CTX;
+
+extern FB_CONSOLE_CTX __fb_con;
+
+extern EM_BOOL fb_hKeyEventHandler(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData);
+extern EM_BOOL fb_hMouseEventHandler(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData);
+extern EM_BOOL fb_hMouseWheelEventHandler(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData);
+
diff --git a/src/rtlib/js/file_copy.c b/src/rtlib/js/file_copy.c
new file mode 100644
index 0000000000..9759b49c12
--- /dev/null
+++ b/src/rtlib/js/file_copy.c
@@ -0,0 +1,8 @@
+/* file copy */
+
+#include "../fb.h"
+
+FBCALL int fb_FileCopy( const char *source, const char *destination )
+{
+ return fb_CrtFileCopy( source, destination );
+}
diff --git a/src/rtlib/js/file_dir.c b/src/rtlib/js/file_dir.c
new file mode 100644
index 0000000000..5115f080cd
--- /dev/null
+++ b/src/rtlib/js/file_dir.c
@@ -0,0 +1,8 @@
+/* dir() */
+
+#include "../fb.h"
+
+FBCALL FBSTRING *fb_Dir( FBSTRING *filespec, int attrib, int *out_attrib )
+{
+ return &__fb_ctx.null_desc;
+}
diff --git a/src/rtlib/js/file_hlock.c b/src/rtlib/js/file_hlock.c
new file mode 100644
index 0000000000..22f7e337db
--- /dev/null
+++ b/src/rtlib/js/file_hlock.c
@@ -0,0 +1,13 @@
+/* low-level lock and unlock functions */
+
+#include "../fb.h"
+
+int fb_hFileLock( FILE *f, fb_off_t inipos, fb_off_t size )
+{
+ return fb_ErrorSetNum( FB_RTERROR_FILEIO );
+}
+
+int fb_hFileUnlock( FILE *f, fb_off_t inipos, fb_off_t size )
+{
+ return fb_ErrorSetNum( FB_RTERROR_FILEIO );
+}
diff --git a/src/rtlib/js/file_hreset.c b/src/rtlib/js/file_hreset.c
new file mode 100644
index 0000000000..303afca519
--- /dev/null
+++ b/src/rtlib/js/file_hreset.c
@@ -0,0 +1,6 @@
+#include "../fb.h"
+
+int fb_hFileResetEx( int streamno )
+{
+ return FALSE;
+}
diff --git a/src/rtlib/js/hinit.c b/src/rtlib/js/hinit.c
new file mode 100644
index 0000000000..cb8b8794b4
--- /dev/null
+++ b/src/rtlib/js/hinit.c
@@ -0,0 +1,64 @@
+/* libfb initialization for js */
+
+#include "../fb.h"
+#include "fb_private_console.h"
+
+FB_CONSOLE_CTX __fb_con;
+
+#ifdef ENABLE_MT
+FBCALL void fb_Lock( void ) { return; }
+FBCALL void fb_Unlock( void ) { return; }
+FBCALL void fb_StrLock( void ) { return; }
+FBCALL void fb_StrUnlock( void ) { return; }
+FBCALL void fb_GraphicsLock ( void ) { return; }
+FBCALL void fb_GraphicsUnlock( void ) { return; }
+#endif
+
+static const char color_remap[16] =
+{
+ [FB_COLOR_BLACK] = 0x1,
+ [FB_COLOR_BLUE] = 0xD,
+ [FB_COLOR_GREEN] = 0xB,
+ [FB_COLOR_CYAN] = 0xF,
+ [FB_COLOR_RED] = 0xA,
+ [FB_COLOR_MAGENTA] = 0xE,
+ [FB_COLOR_BROWN] = 0xC,
+ [FB_COLOR_WHITE] = 0x8,
+ [FB_COLOR_GREY] = 0x9,
+ [FB_COLOR_LBLUE] = 0x5,
+ [FB_COLOR_LGREEN] = 0x3,
+ [FB_COLOR_LCYAN] = 0x7,
+ [FB_COLOR_LRED] = 0x2,
+ [FB_COLOR_LMAGENTA] = 0x6,
+ [FB_COLOR_YELLOW] = 0x4,
+ [FB_COLOR_BWHITE] = 0x8,
+};
+
+static void fb_fs_init_console(void)
+{
+ memset( &__fb_con, 0, sizeof(__fb_con) );
+
+ __fb_con.color_remap = color_remap;
+
+ // keyboard
+ emscripten_set_keypress_callback( 0, NULL, 1, fb_hKeyEventHandler );
+ emscripten_set_keydown_callback( 0, NULL, 1, fb_hKeyEventHandler );
+ emscripten_set_keyup_callback( 0, NULL, 1, fb_hKeyEventHandler );
+
+ // mouse
+ emscripten_set_mousemove_callback( 0, NULL, 1, fb_hMouseEventHandler );
+ emscripten_set_mousedown_callback( 0, NULL, 1, fb_hMouseEventHandler );
+ emscripten_set_mouseup_callback( 0, NULL, 1, fb_hMouseEventHandler );
+ emscripten_set_dblclick_callback( 0, NULL, 1, fb_hMouseEventHandler );
+ //emscripten_set_wheel_callback( 0, NULL, 1, fb_hMouseWheelEventHandler );
+}
+
+void fb_hInit( void )
+{
+ fb_fs_init_console();
+}
+
+void fb_hEnd( int unused )
+{
+}
+
diff --git a/src/rtlib/js/io_cls.c b/src/rtlib/js/io_cls.c
new file mode 100644
index 0000000000..55a1b27d0b
--- /dev/null
+++ b/src/rtlib/js/io_cls.c
@@ -0,0 +1,11 @@
+/* console CLS statement */
+
+#include "../fb.h"
+#include "fb_private_console.h"
+
+void fb_ConsoleClear( int mode )
+{
+ EM_ASM({
+ __fb_rtlib.console.clear();
+ });
+}
diff --git a/src/rtlib/js/io_color.c b/src/rtlib/js/io_color.c
new file mode 100644
index 0000000000..70f7f4dd17
--- /dev/null
+++ b/src/rtlib/js/io_color.c
@@ -0,0 +1,31 @@
+/* console COLOR statement */
+
+#include "../fb.h"
+#include "fb_private_console.h"
+
+static int last_bc = FB_COLOR_BLACK, last_fc = FB_COLOR_WHITE;
+
+int fb_ConsoleColor( int fc, int bc, int flags )
+{
+ int cur = last_fc | (last_bc << 16);
+
+ if( !( flags & FB_COLOR_FG_DEFAULT ) )
+ last_fc = fc & 15;
+
+ if( !( flags & FB_COLOR_BG_DEFAULT ) )
+ last_bc = bc & 15;
+
+ char fc_c = __fb_con.color_remap[last_fc];
+ char bc_c = __fb_con.color_remap[last_bc];
+
+ EM_ASM_ARGS({
+ __fb_rtlib.console.color_set($0, $1);
+ }, fc_c, bc_c);
+
+ return cur;
+}
+
+int fb_ConsoleGetColorAtt( void )
+{
+ return last_fc | (last_bc << 4);
+}
diff --git a/src/rtlib/js/io_getsize.c b/src/rtlib/js/io_getsize.c
new file mode 100644
index 0000000000..258ee7cab2
--- /dev/null
+++ b/src/rtlib/js/io_getsize.c
@@ -0,0 +1,12 @@
+#include "../fb.h"
+#include "fb_private_console.h"
+
+FBCALL void fb_ConsoleGetSize( int *cols, int *rows )
+{
+ int res = EM_ASM_INT({
+ return __fb_rtlib.console.size_get();
+ }, NULL);
+
+ *cols = res & 0xFF;
+ *rows = (res >> 8) & 0xFF;
+}
diff --git a/src/rtlib/js/io_getx.c b/src/rtlib/js/io_getx.c
new file mode 100644
index 0000000000..93aaea3e72
--- /dev/null
+++ b/src/rtlib/js/io_getx.c
@@ -0,0 +1,11 @@
+#include "../fb.h"
+#include "fb_private_console.h"
+
+int fb_ConsoleGetX( void )
+{
+ int res = EM_ASM_INT({
+ return __fb_rtlib.console.pos_get();
+ },NULL);
+
+ return 1+(res & 0xFF);
+}
diff --git a/src/rtlib/js/io_getxy.c b/src/rtlib/js/io_getxy.c
new file mode 100644
index 0000000000..813e7a04d6
--- /dev/null
+++ b/src/rtlib/js/io_getxy.c
@@ -0,0 +1,15 @@
+#include "../fb.h"
+#include "fb_private_console.h"
+
+FBCALL void fb_ConsoleGetXY( int *col, int *row )
+{
+ int res = EM_ASM_INT({
+ return __fb_rtlib.console.pos_get();
+ },NULL);
+
+ if( col != NULL )
+ *col = 1+(res & 0xFF);
+
+ if( row != NULL )
+ *row = 1+((res >> 8) & 0xFF);
+}
diff --git a/src/rtlib/js/io_gety.c b/src/rtlib/js/io_gety.c
new file mode 100644
index 0000000000..1e8957a260
--- /dev/null
+++ b/src/rtlib/js/io_gety.c
@@ -0,0 +1,11 @@
+#include "../fb.h"
+#include "fb_private_console.h"
+
+int fb_ConsoleGetY( void )
+{
+ int res = EM_ASM_INT(
+ return __fb_rtlib.console.pos_get();
+ ,NULL);
+
+ return 1+((res >> 8) & 0xFF);
+}
diff --git a/src/rtlib/js/io_inkey.c b/src/rtlib/js/io_inkey.c
new file mode 100644
index 0000000000..9cc724f4af
--- /dev/null
+++ b/src/rtlib/js/io_inkey.c
@@ -0,0 +1,35 @@
+/* console INKEY() function */
+
+#include "../fb.h"
+#include "fb_private_console.h"
+
+/* Caller is expected to hold FB_LOCK() */
+FBSTRING *fb_ConsoleInkey( void )
+{
+ FBSTRING *res = &__fb_ctx.null_desc;
+
+ if( fb_ConsoleKeyHit( ) != 0 )
+ {
+ res = fb_hMakeInkeyStr( fb_ConsoleGetkey( ) );
+ }
+
+ return res;
+}
+
+int fb_ConsoleGetkey( void )
+{
+ /* !!!FIXME!!! getkey() should block */
+ if( __fb_con.key_head == __fb_con.key_tail)
+ return 0;
+
+ int key = __fb_con.key_buffer[__fb_con.key_head];
+ __fb_con.key_head = (__fb_con.key_head + 1) % KEY_BUFFER_LEN;
+
+ return key;
+}
+
+/* Caller is expected to hold FB_LOCK() */
+int fb_ConsoleKeyHit( void )
+{
+ return __fb_con.key_head != __fb_con.key_tail;
+}
diff --git a/src/rtlib/js/io_input.c b/src/rtlib/js/io_input.c
new file mode 100644
index 0000000000..aae35d12ec
--- /dev/null
+++ b/src/rtlib/js/io_input.c
@@ -0,0 +1,408 @@
+/* console input helpers */
+
+#include "../fb.h"
+#include "fb_private_console.h"
+#include
+
+// QB key codes that are processed by keydown
+static const unsigned short js_keycode_to_qb_key_tb[128] =
+{
+ [ 8] = 8, /* backspace */
+ [ 9] = 9, /* tab */
+ [ 13] = 13, /* enter */
+ [ 27] = 27, /* esc */
+ [ 33] = QB_EXTK(73), /* pgup */
+ [ 34] = QB_EXTK(81), /* pgdown */
+ [ 35] = QB_EXTK(79), /* end */
+ [ 36] = QB_EXTK(71), /* home */
+ [ 37] = QB_EXTK(75), /* left */
+ [ 38] = QB_EXTK(72), /* up */
+ [ 39] = QB_EXTK(77), /* right */
+ [ 40] = QB_EXTK(80), /* down */
+ [ 45] = QB_EXTK(82), /* insert */
+ [ 46] = QB_EXTK(83), /* delete */
+ [112] = QB_EXTK(59), /* F1 */
+ [113] = QB_EXTK(60), /* F2 */
+ [114] = QB_EXTK(61), /* F3 */
+ [115] = QB_EXTK(62), /* F4 */
+ [116] = QB_EXTK(63), /* F5 */
+ [117] = QB_EXTK(64), /* F6 */
+ [118] = QB_EXTK(65), /* F7 */
+ [119] = QB_EXTK(66), /* F8 */
+ [120] = QB_EXTK(67), /* F9 */
+ [121] = QB_EXTK(68), /* F10 */
+ [122] = QB_EXTK(133), /* F11 */
+ [123] = QB_EXTK(134), /* F12 */
+};
+
+// QB key codes returned when CTRL is pressed
+static const unsigned short js_keycode_to_qb_key_ctrl_tb[128] =
+{
+ [ 8] = 127, /* backspace */
+ [ 13] = 10, /* enter */
+ [ 32] = 32, /* espace */
+ [ 33] = QB_EXTK(132), /* pgup */
+ [ 34] = QB_EXTK(118), /* pgdown */
+ [ 35] = QB_EXTK(117), /* end */
+ [ 36] = QB_EXTK(119), /* home */
+ [ 37] = QB_EXTK(115), /* left */
+ [ 38] = QB_EXTK(141), /* up */
+ [ 39] = QB_EXTK(116), /* right */
+ [ 40] = QB_EXTK(145), /* down */
+ [ 45] = QB_EXTK(146), /* insert */
+ [ 46] = QB_EXTK(147), /* delete */
+ [ 65] = 1, /* A */
+ [ 66] = 2, /* B */
+ [ 67] = 3, /* C */
+ [ 68] = 4, /* D */
+ [ 69] = 5, /* E */
+ [ 70] = 6, /* F */
+ [ 71] = 7, /* G */
+ [ 72] = 8, /* H */
+ [ 73] = 9, /* I */
+ [ 74] = 10, /* J */
+ [ 75] = 11, /* K */
+ [ 76] = 12, /* L */
+ [ 77] = 13, /* M */
+ [ 78] = 14, /* N */
+ [ 79] = 15, /* O */
+ [ 80] = 16, /* P */
+ [ 81] = 17, /* Q */
+ [ 82] = 18, /* R */
+ [ 83] = 19, /* S */
+ [ 84] = 20, /* T */
+ [ 85] = 21, /* U */
+ [ 86] = 22, /* V */
+ [ 87] = 23, /* W */
+ [ 88] = 24, /* X */
+ [ 89] = 25, /* Y */
+ [ 90] = 26, /* Z */
+ [ 91] = 27, /* [ */
+ [ 92] = 28, /* \ */
+ [ 93] = 29, /* ] */
+ [112] = QB_EXTK(94), /* F1 */
+ [113] = QB_EXTK(95), /* F2 */
+ [114] = QB_EXTK(96), /*__fb_ctx.hooks.posteventproc(&fb_event); F3 */
+ [115] = QB_EXTK(97), /* F4 */
+ [116] = QB_EXTK(98), /* F5 */
+ [117] = QB_EXTK(99), /* F6 */
+ [118] = QB_EXTK(100), /* F7 */
+ [119] = QB_EXTK(101), /* F8 */
+ [120] = QB_EXTK(102), /* F9 */
+ [121] = QB_EXTK(103), /* F10 */
+ [122] = QB_EXTK(137), /* F11 */
+ [123] = QB_EXTK(138), /* F12 */
+};
+
+// keycodes that should not be remapped by keydown
+static const unsigned char js_keycode_to_not_process_tb[256] =
+{
+ [ 16] = 1, /* shift */
+ [ 17] = 1, /* ctrl */
+ [ 18] = 1, /* alt */
+ [ 20] = 1, /* capslock */
+ [ 32] = 1, /* espace */
+ [ 59] = 1, /* ; */
+ [ 61] = 1, /* = */
+ [ 91] = 1, /* lwin */
+ [ 93] = 1, /* menu */
+ [144] = 1, /* numlock */
+ [145] = 1, /* scrolllock */
+ [173] = 1, /* - */
+ [176] = 1, /* ~ */
+ [188] = 1, /* , */
+ [190] = 1, /* . */
+ [191] = 1, /* / */
+ [219] = 1, /* [ */
+ [220] = 1, /* \ */
+ [221] = 1, /* ] */
+ [222] = 1, /* ' */
+};
+
+// keyboard scan codes returned my MultiKey()
+static const unsigned char js_keycode_to_qb_scancode_tb[256] =
+{
+ [ 8] = SC_BACKSPACE,
+ [ 9] = SC_TAB,
+ [ 13] = SC_ENTER,
+ [ 20] = SC_CAPSLOCK,
+ [ 27] = SC_ESCAPE,
+ [ 32] = SC_SPACE,
+ [ 33] = SC_PAGEUP,
+ [ 34] = SC_PAGEDOWN,
+ [ 35] = SC_END,
+ [ 36] = SC_HOME,
+ [ 37] = SC_LEFT,
+ [ 38] = SC_UP,
+ [ 39] = SC_RIGHT,
+ [ 40] = SC_DOWN,
+ [ 45] = SC_INSERT,
+ [ 46] = SC_DELETE,
+ [ 48] = SC_0,
+ [ 49] = SC_1,
+ [ 50] = SC_2,
+ [ 51] = SC_3,
+ [ 52] = SC_4,
+ [ 53] = SC_5,
+ [ 54] = SC_6,
+ [ 55] = SC_7,
+ [ 56] = SC_8,
+ [ 57] = SC_9,
+ [ 59] = SC_SEMICOLON,
+ [ 61] = SC_EQUALS,
+ [ 65] = SC_A,
+ [ 66] = SC_B,
+ [ 67] = SC_C,
+ [ 68] = SC_D,
+ [ 69] = SC_E,
+ [ 70] = SC_F,
+ [ 71] = SC_G,
+ [ 72] = SC_H,
+ [ 73] = SC_I,
+ [ 74] = SC_J,
+ [ 75] = SC_K,
+ [ 76] = SC_L,
+ [ 77] = SC_M,
+ [ 78] = SC_N,
+ [ 79] = SC_O,
+ [ 80] = SC_P,
+ [ 81] = SC_Q,
+ [ 82] = SC_R,
+ [ 83] = SC_S,
+ [ 84] = SC_T,
+ [ 85] = SC_U,
+ [ 86] = SC_V,
+ [ 87] = SC_W,
+ [ 88] = SC_X,
+ [ 89] = SC_Y,
+ [ 90] = SC_Z,
+ [ 93] = SC_MENU,
+ [106] = SC_MULTIPLY, /* * (numpad) */
+ [107] = SC_PLUS, /* + (numpad) */
+ [108] = SC_PERIOD, /* . (numpad) */
+ [109] = SC_MINUS, /* - (numpad) */
+ [110] = SC_COMMA, /* , (numpad) */
+ [111] = SC_SLASH, /* / (numpad) */
+ [112] = SC_F1,
+ [113] = SC_F2,
+ [114] = SC_F3,
+ [115] = SC_F4,
+ [116] = SC_F5,
+ [117] = SC_F6,
+ [118] = SC_F7,
+ [119] = SC_F8,
+ [120] = SC_F9,
+ [121] = SC_F10,
+ [122] = SC_F11,
+ [123] = SC_F12,
+ [144] = SC_NUMLOCK,
+ [145] = SC_SCROLLLOCK,
+ [173] = SC_MINUS,
+ [176] = SC_TILDE,
+ [188] = SC_COMMA,
+ [190] = SC_PERIOD,
+ [191] = SC_SLASH,
+ [219] = SC_LEFTBRACKET,
+ [220] = SC_BACKSLASH,
+ [221] = SC_RIGHTBRACKET,
+ [222] = SC_QUOTE,
+};
+
+static unsigned int js_keycode_to_qb_key(const EmscriptenKeyboardEvent *keyEvent)
+{
+ unsigned int key = keyEvent->keyCode;
+
+ // numpad?
+ if( keyEvent->location == 3 )
+ {
+ // numlock on? let keypress process it
+ if( key > 46 )
+ return 0;
+ }
+
+ // ctrl? remap to the special qb keys
+ if( keyEvent->ctrlKey )
+ {
+ if( key < 128 )
+ key = js_keycode_to_qb_key_ctrl_tb[key];
+ }
+ else
+ {
+ // printable character or other key that should not be returned to inkey()? let keypress do the rest
+ if( (key >= 'A' && key <= 'Z') ||
+ (key >= '0' && key <= '9') ||
+ (key < 256 && js_keycode_to_not_process_tb[key] != 0) )
+ {
+ return 0;
+ }
+ else
+ {
+ // remap to QB key code
+ if( key < 128 )
+ {
+ unsigned short qbkey = js_keycode_to_qb_key_tb[key];
+ if( qbkey != 0 )
+ key = qbkey;
+ }
+ }
+ }
+
+ return key;
+}
+
+static unsigned int js_multikey_handler(unsigned long key, unsigned long location, int isKeyDown)
+{
+ unsigned int scancode = 0;
+
+ if( key < 256 )
+ {
+ switch( key )
+ {
+ // shift?
+ case 16:
+ /* location == 1? left-shift: right-shift */
+ scancode = location == 1? SC_LSHIFT: SC_RSHIFT;
+ break;
+
+ // ctrl?
+ case 17:
+ /* location == 1? left-ctrl: right-ctrl */
+ scancode = location == 1? SC_CONTROL: SC_CONTROL;
+ break;
+
+ // alt?
+ case 18:
+ /* location == 1? left-alt: alt-gr */
+ scancode = location == 1? SC_ALT: SC_ALTGR;
+ break;
+
+ // win?
+ case 91:
+ /* location == 1? lwin: rwin */
+ scancode = location == 1? SC_LWIN: SC_RWIN;
+ break;
+
+ default:
+ scancode = js_keycode_to_qb_scancode_tb[key];
+ break;
+ }
+
+ __fb_con.multikey[scancode] = isKeyDown? 1: 0;
+ }
+
+ return scancode;
+}
+
+static void js_key_buffer_add(unsigned int key)
+{
+ __fb_con.key_buffer[__fb_con.key_tail] = key;
+ __fb_con.key_tail = (__fb_con.key_tail + 1) % KEY_BUFFER_LEN;
+
+ if( __fb_con.key_tail == __fb_con.key_head )
+ __fb_con.key_head = (__fb_con.key_head + 1) % KEY_BUFFER_LEN;
+
+}
+
+EM_BOOL fb_hKeyEventHandler(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)
+{
+ static unsigned int scancode;
+ static unsigned int keycode;
+
+ switch( eventType )
+ {
+ case EMSCRIPTEN_EVENT_KEYDOWN:
+ {
+ EM_BOOL supress_keypress = 0;
+ if( keyEvent->keyCode != 0)
+ {
+ keycode = js_keycode_to_qb_key( keyEvent );
+ if( keycode != 0 )
+ {
+ js_key_buffer_add(keycode);
+ // as the key code was added to Inkey's buffer, supress the keypress handler
+ supress_keypress = 1;
+ }
+
+ scancode = js_multikey_handler(keyEvent->keyCode, keyEvent->location, TRUE);
+
+ if( supress_keypress )
+ {
+ if(__fb_ctx.hooks.posteventproc != NULL)
+ {
+ EVENT fb_event = { .type = EVENT_KEY_PRESS, .scancode = scancode, .ascii = scancode };
+ __fb_ctx.hooks.posteventproc(&fb_event);
+ }
+
+ }
+ }
+
+ return supress_keypress;
+ }
+
+ case EMSCRIPTEN_EVENT_KEYPRESS:
+ {
+ // printable char and CTRL not pressed? add it to Inkey's buffer..
+ keycode = keyEvent->charCode;
+ if( keycode != 0)
+ {
+ if( keyEvent->ctrlKey == 0)
+ {
+ js_key_buffer_add(keycode);
+
+ if(__fb_ctx.hooks.posteventproc != NULL)
+ {
+ EVENT fb_event = { .type = EVENT_KEY_PRESS, .scancode = scancode, .ascii = keycode };
+ __fb_ctx.hooks.posteventproc(&fb_event);
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ case EMSCRIPTEN_EVENT_KEYUP:
+ {
+ scancode = js_multikey_handler(keyEvent->keyCode, keyEvent->location, FALSE);
+
+ if(__fb_ctx.hooks.posteventproc != NULL)
+ {
+ EVENT fb_event = { .type = EVENT_KEY_RELEASE, .scancode = scancode, .ascii = keycode };
+ __fb_ctx.hooks.posteventproc(&fb_event);
+ }
+
+ return 1;
+ }
+
+ default:
+ {
+ return 0;
+ }
+ }
+}
+
+EM_BOOL fb_hMouseEventHandler(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)
+{
+ switch( eventType )
+ {
+ case EMSCRIPTEN_EVENT_MOUSEMOVE:
+ case EMSCRIPTEN_EVENT_MOUSEDOWN:
+ case EMSCRIPTEN_EVENT_MOUSEUP:
+ case EMSCRIPTEN_EVENT_DBLCLICK:
+ {
+ __fb_con.mouse.x = mouseEvent->clientX;
+ __fb_con.mouse.y = mouseEvent->clientY;
+ __fb_con.mouse.dx = mouseEvent->movementX;
+ __fb_con.mouse.dy = mouseEvent->movementY;
+ __fb_con.mouse.button = mouseEvent->button == 0? BUTTON_LEFT: (mouseEvent->button == 1? BUTTON_MIDDLE: BUTTON_RIGHT);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int fb_hConsoleInputBufferChanged( void )
+{
+ return fb_ConsoleKeyHit();
+}
+
diff --git a/src/rtlib/js/io_isredir.c b/src/rtlib/js/io_isredir.c
new file mode 100644
index 0000000000..0bcc1c66bc
--- /dev/null
+++ b/src/rtlib/js/io_isredir.c
@@ -0,0 +1,6 @@
+#include "../fb.h"
+
+int fb_ConsoleIsRedirected( int is_input )
+{
+ return FB_TRUE;
+}
diff --git a/src/rtlib/js/io_locate.c b/src/rtlib/js/io_locate.c
new file mode 100644
index 0000000000..68dda79360
--- /dev/null
+++ b/src/rtlib/js/io_locate.c
@@ -0,0 +1,32 @@
+/* console LOCATE statement */
+
+#include "../fb.h"
+#include "fb_private_console.h"
+
+int fb_ConsoleLocate( int row, int col, int cursor )
+{
+ if( row > 0 || col > 0 )
+ {
+ EM_ASM_ARGS({
+ __fb_rtlib.console.pos_set($0, $1);
+ }, row-1, col-1);
+ }
+
+ if( cursor != -1 )
+ {
+ if( cursor == 0 )
+ {
+ EM_ASM({
+ __fb_rtlib.console.cursor_hide();
+ });
+ }
+ else
+ {
+ EM_ASM({
+ __fb_rtlib.console.cursor_show();
+ });
+ }
+ }
+
+ return (col & 0xFF) | ((row & 0xFF) << 8);
+}
diff --git a/src/rtlib/js/io_maxrow.c b/src/rtlib/js/io_maxrow.c
new file mode 100644
index 0000000000..d4598c7373
--- /dev/null
+++ b/src/rtlib/js/io_maxrow.c
@@ -0,0 +1,7 @@
+#include "../fb.h"
+#include "fb_private_console.h"
+
+int fb_ConsoleGetMaxRow( void )
+{
+ return 100;
+}
diff --git a/src/rtlib/js/io_mouse.c b/src/rtlib/js/io_mouse.c
new file mode 100644
index 0000000000..c9b6017ff6
--- /dev/null
+++ b/src/rtlib/js/io_mouse.c
@@ -0,0 +1,49 @@
+/* console mode mouse functions */
+
+#include "../fb.h"
+#include "fb_private_console.h"
+#include "../../gfxlib2/fb_gfx.h"
+
+int fb_ConsoleGetMouse( int *x, int *y, int *z, int *buttons, int *clip )
+{
+ EmscriptenMouseEvent mouseState;
+
+ if( emscripten_get_mouse_status( &mouseState ) != EMSCRIPTEN_RESULT_SUCCESS )
+ return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL );
+
+ if( x != NULL )
+ *x = mouseState.clientX;
+
+ if( y != NULL )
+ *y = mouseState.clientY;
+
+ if( z != NULL )
+ *z = 0;
+
+ if( buttons != NULL )
+ {
+ int mbuttons = 0;
+ if( mouseState.buttons & 1)
+ mbuttons |= BUTTON_LEFT;
+ if( mouseState.buttons & 2)
+ mbuttons |= BUTTON_RIGHT;
+ if( mouseState.buttons & 4)
+ mbuttons |= BUTTON_MIDDLE;
+ if( mouseState.buttons & 8)
+ mbuttons |= BUTTON_X1;
+ if( mouseState.buttons & 16)
+ mbuttons |= BUTTON_X2;
+
+ *buttons = mbuttons;
+ }
+
+ if( clip != NULL )
+ *clip = 0;
+
+ return fb_ErrorSetNum( FB_RTERROR_OK );
+}
+
+int fb_ConsoleSetMouse( int x, int y, int cursor, int clip )
+{
+ return fb_ErrorSetNum( FB_RTERROR_OK );
+}
diff --git a/src/rtlib/js/io_multikey.c b/src/rtlib/js/io_multikey.c
new file mode 100644
index 0000000000..59aff525c7
--- /dev/null
+++ b/src/rtlib/js/io_multikey.c
@@ -0,0 +1,12 @@
+/* console multikey() */
+
+#include "../fb.h"
+#include "fb_private_console.h"
+
+int fb_ConsoleMultikey( int scancode )
+{
+ if( scancode < 0 || scancode > 255 )
+ fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL );
+
+ return __fb_con.multikey[scancode] != 0? FB_TRUE: FB_FALSE;
+}
diff --git a/src/rtlib/js/io_pageset.c b/src/rtlib/js/io_pageset.c
new file mode 100644
index 0000000000..2888620c9e
--- /dev/null
+++ b/src/rtlib/js/io_pageset.c
@@ -0,0 +1,8 @@
+/* console 'screen , pg, pg' function */
+
+#include "../fb.h"
+
+int fb_ConsolePageSet( int active, int visible )
+{
+ return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL );
+}
diff --git a/src/rtlib/js/io_pcopy.c b/src/rtlib/js/io_pcopy.c
new file mode 100644
index 0000000000..d00eac3a18
--- /dev/null
+++ b/src/rtlib/js/io_pcopy.c
@@ -0,0 +1,8 @@
+/* console pcopy function */
+
+#include "../fb.h"
+
+int fb_ConsolePageCopy( int src, int dst )
+{
+ return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL );
+}
diff --git a/src/rtlib/js/io_printbuff.c b/src/rtlib/js/io_printbuff.c
new file mode 100644
index 0000000000..f9422b8396
--- /dev/null
+++ b/src/rtlib/js/io_printbuff.c
@@ -0,0 +1,16 @@
+/* low-level print to console function stub */
+
+#include "../fb.h"
+#include "fb_private_console.h"
+
+void fb_ConsolePrintBufferEx( const void *buffer, size_t len, int mask )
+{
+ EM_ASM_ARGS({
+ __fb_rtlib.console.writeSubs(UTF8ToString($0), $1);
+ }, buffer, len );
+}
+
+void fb_ConsolePrintBuffer( const char *buffer, int mask )
+{
+ fb_ConsolePrintBufferEx( buffer, strlen(buffer), mask );
+}
diff --git a/src/rtlib/js/io_printbuff_wstr.c b/src/rtlib/js/io_printbuff_wstr.c
new file mode 100644
index 0000000000..c276362304
--- /dev/null
+++ b/src/rtlib/js/io_printbuff_wstr.c
@@ -0,0 +1,23 @@
+/* low-level print to console function */
+
+#include "../fb.h"
+
+void fb_ConsolePrintBufferWstrEx
+ (
+ const FB_WCHAR *buffer,
+ size_t chars,
+ int mask
+ )
+{
+ /* !!!FIXME!!! should print only buffer[0 .. chars-1] */
+ wprintf( L"%ls", buffer );
+}
+
+void fb_ConsolePrintBufferWstr
+ (
+ const FB_WCHAR *buffer,
+ int mask
+ )
+{
+ return fb_ConsolePrintBufferWstrEx( buffer, fb_wstr_Len( buffer ), mask );
+}
diff --git a/src/rtlib/js/io_printer.c b/src/rtlib/js/io_printer.c
new file mode 100644
index 0000000000..b54445a432
--- /dev/null
+++ b/src/rtlib/js/io_printer.c
@@ -0,0 +1,23 @@
+/* printer access stubs */
+
+#include "../fb.h"
+
+int fb_PrinterOpen( DEV_LPT_INFO *devInfo, int iPort, const char *pszDevice )
+{
+ return fb_ErrorSetNum( FB_RTERROR_FILENOTFOUND );
+}
+
+int fb_PrinterWrite( DEV_LPT_INFO *devInfo, const void *data, size_t length )
+{
+ return fb_ErrorSetNum( FB_RTERROR_FILEIO );
+}
+
+int fb_PrinterWriteWstr( DEV_LPT_INFO *devInfo, const FB_WCHAR *data, size_t length )
+{
+ return fb_ErrorSetNum( FB_RTERROR_FILEIO );
+}
+
+int fb_PrinterClose( DEV_LPT_INFO *devInfo )
+{
+ return fb_ErrorSetNum( FB_RTERROR_FILEIO );
+}
diff --git a/src/rtlib/js/io_readstr.c b/src/rtlib/js/io_readstr.c
new file mode 100644
index 0000000000..8ad2f7c4ec
--- /dev/null
+++ b/src/rtlib/js/io_readstr.c
@@ -0,0 +1,8 @@
+/* console line input function */
+
+#include "../fb.h"
+
+char *fb_ConsoleReadStr( char *buffer, ssize_t len )
+{
+ return fgets( buffer, len, stdin );
+}
diff --git a/src/rtlib/js/io_readxy.c b/src/rtlib/js/io_readxy.c
new file mode 100644
index 0000000000..3f75152c5d
--- /dev/null
+++ b/src/rtlib/js/io_readxy.c
@@ -0,0 +1,20 @@
+/* console SCREEN() function (character/color query) */
+
+#include "../fb.h"
+#include "fb_private_console.h"
+
+FBCALL unsigned int fb_ConsoleReadXY( int col, int row, int colorflag )
+{
+ unsigned int res = 0;
+
+ if( colorflag )
+ res = EM_ASM_INT({
+ __fb_rtlib.console.charAt($0, $1)
+ }, col-1, row-1);
+ else
+ res = EM_ASM_INT({
+ __fb_rtlib.console.colorAt($0, $1)
+ }, col-1, row-1);
+
+ return res;
+}
diff --git a/src/rtlib/js/io_scroll.c b/src/rtlib/js/io_scroll.c
new file mode 100644
index 0000000000..c7cc14df66
--- /dev/null
+++ b/src/rtlib/js/io_scroll.c
@@ -0,0 +1,8 @@
+/* console scrolling for when VIEW is used */
+
+#include "../fb.h"
+
+void fb_ConsoleScroll( int nrows )
+{
+ /* !!!WRITEME!!! */
+}
diff --git a/src/rtlib/js/io_serial.c b/src/rtlib/js/io_serial.c
new file mode 100644
index 0000000000..670f62196d
--- /dev/null
+++ b/src/rtlib/js/io_serial.c
@@ -0,0 +1,35 @@
+/* serial port access stubs */
+
+#include "../fb.h"
+
+int fb_SerialOpen
+ (
+ FB_FILE *handle,
+ int iPort,
+ FB_SERIAL_OPTIONS *options,
+ const char *pszDevice,
+ void **ppvHandle
+ )
+{
+ return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL );
+}
+
+int fb_SerialGetRemaining( FB_FILE *handle, void *pvHandle, fb_off_t *pLength )
+{
+ return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL );
+}
+
+int fb_SerialWrite( FB_FILE *handle, void *pvHandle, const void *data, size_t length )
+{
+ return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL );
+}
+
+int fb_SerialRead( FB_FILE *handle, void *pvHandle, void *data, size_t *pLength )
+{
+ return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL );
+}
+
+int fb_SerialClose( FB_FILE *handle, void *pvHandle )
+{
+ return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL );
+}
diff --git a/src/rtlib/js/io_viewupdate.c b/src/rtlib/js/io_viewupdate.c
new file mode 100644
index 0000000000..799ee210b3
--- /dev/null
+++ b/src/rtlib/js/io_viewupdate.c
@@ -0,0 +1,7 @@
+/* view print update (console, no gfx) */
+
+#include "../fb.h"
+
+void fb_ConsoleViewUpdate( void )
+{
+}
diff --git a/src/rtlib/js/io_width.c b/src/rtlib/js/io_width.c
new file mode 100644
index 0000000000..70b2127825
--- /dev/null
+++ b/src/rtlib/js/io_width.c
@@ -0,0 +1,19 @@
+/* console width() function */
+
+#include "../fb.h"
+#include "fb_private_console.h"
+
+int fb_ConsoleWidth( int cols, int rows )
+{
+ if( cols < 40 )
+ cols = 40;
+
+ if( rows < 10 )
+ rows = 10;
+
+ EM_ASM_ARGS({
+ __fb_rtlib.console.size_set($0, $1);
+ },cols, rows);
+
+ return (rows << 16) | cols;
+}
diff --git a/src/rtlib/js/sys_beep.c b/src/rtlib/js/sys_beep.c
new file mode 100644
index 0000000000..177112fcc6
--- /dev/null
+++ b/src/rtlib/js/sys_beep.c
@@ -0,0 +1,8 @@
+/* beep function */
+
+#include "../fb.h"
+
+FBCALL void fb_Beep( void )
+{
+ return;
+}
diff --git a/src/rtlib/js/sys_delay.c b/src/rtlib/js/sys_delay.c
new file mode 100644
index 0000000000..9d21b87ade
--- /dev/null
+++ b/src/rtlib/js/sys_delay.c
@@ -0,0 +1,6 @@
+#include "../fb.h"
+
+FBCALL void fb_Delay( int msecs )
+{
+ return;
+}
diff --git a/src/rtlib/js/sys_dylib.c b/src/rtlib/js/sys_dylib.c
new file mode 100644
index 0000000000..b6ee97e279
--- /dev/null
+++ b/src/rtlib/js/sys_dylib.c
@@ -0,0 +1,22 @@
+/* Dynamic library loading functions */
+
+#include "../fb.h"
+
+FBCALL void *fb_DylibLoad( FBSTRING *library )
+{
+ return NULL;
+}
+
+FBCALL void *fb_DylibSymbol( void *library, FBSTRING *symbol )
+{
+ return NULL;
+}
+
+FBCALL void *fb_DylibSymbolByOrd( void *library, short int symbol )
+{
+ return NULL;
+}
+
+FBCALL void fb_DylibFree( void *library )
+{
+}
diff --git a/src/rtlib/js/sys_execex.c b/src/rtlib/js/sys_execex.c
new file mode 100644
index 0000000000..439a36064e
--- /dev/null
+++ b/src/rtlib/js/sys_execex.c
@@ -0,0 +1,6 @@
+#include "../fb.h"
+
+FBCALL int fb_ExecEx( FBSTRING *program, FBSTRING *args, int do_fork )
+{
+ return fb_ErrorSetNum(FB_RTERROR_FILENOTFOUND);
+}
diff --git a/src/rtlib/js/sys_fmem.c b/src/rtlib/js/sys_fmem.c
new file mode 100644
index 0000000000..137961b424
--- /dev/null
+++ b/src/rtlib/js/sys_fmem.c
@@ -0,0 +1,8 @@
+/* fre() function */
+
+#include "../fb.h"
+
+FBCALL size_t fb_GetMemAvail( int mode )
+{
+ return 16 * 1024 * 1024;
+}
diff --git a/src/rtlib/js/sys_getcwd.c b/src/rtlib/js/sys_getcwd.c
new file mode 100644
index 0000000000..82991fe5bc
--- /dev/null
+++ b/src/rtlib/js/sys_getcwd.c
@@ -0,0 +1,9 @@
+/* get current dir */
+
+#include "../fb.h"
+
+ssize_t fb_hGetCurrentDir( char *dst, ssize_t maxlen )
+{
+ *dst = '\0';
+ return 0;
+}
diff --git a/src/rtlib/js/sys_getexename.c b/src/rtlib/js/sys_getexename.c
new file mode 100644
index 0000000000..6eac1f2dcb
--- /dev/null
+++ b/src/rtlib/js/sys_getexename.c
@@ -0,0 +1,9 @@
+/* get the executable's name */
+
+#include "../fb.h"
+
+char *fb_hGetExeName( char *dst, ssize_t maxlen )
+{
+ dst[0] = '\0';
+ return dst;
+}
diff --git a/src/rtlib/js/sys_getexepath.c b/src/rtlib/js/sys_getexepath.c
new file mode 100644
index 0000000000..61aa4be96a
--- /dev/null
+++ b/src/rtlib/js/sys_getexepath.c
@@ -0,0 +1,9 @@
+/* get the executable path */
+
+#include "../fb.h"
+
+char *fb_hGetExePath( char *dst, ssize_t maxlen )
+{
+ dst[0] = '\0';
+ return dst;
+}
diff --git a/src/rtlib/js/sys_getshortpath.c b/src/rtlib/js/sys_getshortpath.c
new file mode 100644
index 0000000000..1f59347c67
--- /dev/null
+++ b/src/rtlib/js/sys_getshortpath.c
@@ -0,0 +1,7 @@
+#include "../fb.h"
+
+char *fb_hGetShortPath( char *src, char *dst, ssize_t maxlen )
+{
+ strncpy(dst, src, maxlen);
+ return dst;
+}
diff --git a/src/rtlib/js/sys_hshell.c b/src/rtlib/js/sys_hshell.c
new file mode 100644
index 0000000000..98a96292e7
--- /dev/null
+++ b/src/rtlib/js/sys_hshell.c
@@ -0,0 +1,8 @@
+/* SHELL command */
+
+#include "../fb.h"
+
+int fb_hShell( char *program )
+{
+ return -1;
+}
diff --git a/src/rtlib/js/thread_cond.c b/src/rtlib/js/thread_cond.c
new file mode 100644
index 0000000000..84dc273fff
--- /dev/null
+++ b/src/rtlib/js/thread_cond.c
@@ -0,0 +1,24 @@
+/* condition variable functions */
+
+#include "../fb.h"
+
+FBCALL FBCOND *fb_CondCreate( void )
+{
+ return NULL;
+}
+
+FBCALL void fb_CondDestroy( FBCOND *cond )
+{
+}
+
+FBCALL void fb_CondSignal( FBCOND *cond )
+{
+}
+
+FBCALL void fb_CondBroadcast( FBCOND *cond )
+{
+}
+
+FBCALL void fb_CondWait( FBCOND *cond, FBMUTEX *mutex )
+{
+}
diff --git a/src/rtlib/js/thread_core.c b/src/rtlib/js/thread_core.c
new file mode 100644
index 0000000000..b63803d0be
--- /dev/null
+++ b/src/rtlib/js/thread_core.c
@@ -0,0 +1,24 @@
+/* thread creation and destruction functions */
+
+#include "../fb.h"
+#include "../fb_private_thread.h"
+
+FBCALL FBTHREAD *fb_ThreadCreate( FB_THREADPROC proc, void *param, ssize_t stack_size )
+{
+ FBTHREAD *thread;
+
+ thread = (FBTHREAD *)malloc( sizeof( FBTHREAD ) );
+ if( thread == NULL ) {
+ return NULL;
+ }
+
+ return thread;
+}
+
+FBCALL void fb_ThreadWait( FBTHREAD *thread )
+{
+ if( !thread )
+ return;
+
+ free( thread );
+}
diff --git a/src/rtlib/js/thread_detach.c b/src/rtlib/js/thread_detach.c
new file mode 100644
index 0000000000..8c9d73be04
--- /dev/null
+++ b/src/rtlib/js/thread_detach.c
@@ -0,0 +1,9 @@
+#include "../fb.h"
+
+FBCALL void fb_ThreadDetach( FBTHREAD *thread )
+{
+ if( thread == NULL )
+ return;
+
+ free( thread );
+}
diff --git a/src/rtlib/js/thread_mutex.c b/src/rtlib/js/thread_mutex.c
new file mode 100644
index 0000000000..3ad2495a95
--- /dev/null
+++ b/src/rtlib/js/thread_mutex.c
@@ -0,0 +1,20 @@
+/* mutex handling routines */
+
+#include "../fb.h"
+
+FBCALL FBMUTEX *fb_MutexCreate( void )
+{
+ return NULL;
+}
+
+FBCALL void fb_MutexDestroy( FBMUTEX *mutex )
+{
+}
+
+FBCALL void fb_MutexLock( FBMUTEX *mutex )
+{
+}
+
+FBCALL void fb_MutexUnlock( FBMUTEX *mutex )
+{
+}
diff --git a/src/rtlib/js/time_setdate.c b/src/rtlib/js/time_setdate.c
new file mode 100644
index 0000000000..a436240dfc
--- /dev/null
+++ b/src/rtlib/js/time_setdate.c
@@ -0,0 +1,8 @@
+/* set date function */
+
+#include "../fb.h"
+
+int fb_hSetDate( int y, int m, int d )
+{
+ return 0;
+}
diff --git a/src/rtlib/js/time_settime.c b/src/rtlib/js/time_settime.c
new file mode 100644
index 0000000000..7d3dc297fe
--- /dev/null
+++ b/src/rtlib/js/time_settime.c
@@ -0,0 +1,6 @@
+#include "../fb.h"
+
+int fb_hSetTime( int h, int m, int s )
+{
+ return 0;
+}
diff --git a/src/rtlib/js/time_timer.c b/src/rtlib/js/time_timer.c
new file mode 100644
index 0000000000..fe12971fd1
--- /dev/null
+++ b/src/rtlib/js/time_timer.c
@@ -0,0 +1,12 @@
+/* timer() function */
+
+#include "../fb.h"
+#include
+#include
+
+FBCALL double fb_Timer( void )
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return (((double)tv.tv_sec * 1000000.0) + (double)tv.tv_usec) * 0.000001;
+}
diff --git a/src/rtlib/xbox/io_getsize.c b/src/rtlib/xbox/io_getsize.c
index 452f178c15..2d9eb1415f 100644
--- a/src/rtlib/xbox/io_getsize.c
+++ b/src/rtlib/xbox/io_getsize.c
@@ -2,4 +2,6 @@
FBCALL void fb_ConsoleGetSize( int *cols, int *rows )
{
+ *cols = 80;
+ *rows = 25;
}
|
| |
|