/* Escape sequences */ // Remove colors var defaultColor = '\x1b[39m' ; // back to the default color, most of time it is the same than .white var bgDefaultColor = '\x1b[49m' ; // back to the default color, most of time it is the same than .bgBlack var esc = { /* Common sequences */ // Reset the terminal reset: { on: '\x1bc' } , /* Cursor sequences */ scrollUp: { on: '\x1b[%US' } , scrollDown: { on: '\x1b[%UT' } , hideCursor: { on: '\x1b[?25l' , off: '\x1b[?25h' } , /* Editing sequences */ // This set the alternate screen buffer, do not work on many term, due to this titeInhibit shit... alternateScreenBuffer: { on: '\x1b[?1049h' , off: '\x1b[?1049l' } , /* Misc sequences */ bell: { on: '\x07' } , // Emit an audible bell /* Input / Output sequences */ // Request terminal ID // requestTerminalId: { on: '\x1b[>c' } , // Terminal will send the cursor coordinate only one time requestCursorLocation: { on: '\x1b[6n' } , // '\x1b[?6n' is not widely supported, '\x1b[6n' is better // Terminal will send the cursor coordinate only one time requestScreenSize: { on: '\x1b[18t' } , // Terminal will send the rgb color for a register requestColor: { on: '\x1b]4;%u;?\x07' } , // Terminal will send event on button pressed with mouse position mouseButton: { on: '\x1b[?1000h' , off: '\x1b[?1000l' } , // Terminal will send position of the column hilighted mouseHilight: { on: '\x1b[?1001h' , off: '\x1b[?1001l' } , // Terminal will send event on button pressed and mouse motion as long as a button is down, with mouse position mouseDrag: { on: '\x1b[?1002h' , off: '\x1b[?1002l' } , // Terminal will send event on button pressed and motion mouseMotion: { on: '\x1b[?1003h' , off: '\x1b[?1003l' } , // Another mouse protocol that extend coordinate mapping (without it, it supports only 223 rows and columns) mouseSGR: { on: '\x1b[?1006h' , off: '\x1b[?1006l' } , // Terminal will send event when it gains and loses focus focusEvent: { on: '\x1b[?1004h' , off: '\x1b[?1004l' } , // Should allow keypad to send different code than 0..9 keys but it does not works on some setup applicationKeypad: { on: '\x1b[?1h\x1b=' , off: '\x1b[?1l\x1b>' } , // When enabled, the terminal will report if modifiers (SHIFT, CTRL, ALT) are on /* Not widely supported keyboardModifier: { on: '\x1b[>0;1m' , off: '\x1b[>0;0m' } , cursorKeyModifier: { on: '\x1b[>1;1m' , off: '\x1b[>1;0m' } , functionKeyModifier: { on: '\x1b[>2;1m' , off: '\x1b[>2;0m' } , otherKeyModifier: { on: '\x1b[>3;1m' , off: '\x1b[>3;0m' } , */ // Do not work... use node.js stdout.setRawMode(true) instead //noecho: { on: '\x1b[12h' } , /* OSC - OS Control sequences: may be unavailable on some context */ // Set the title of an xterm-compatible window windowTitle: { on: '\x1b]0;%s\x1b\\' } , // Those sequences accept either #%x%x%x or rgb:%d/%d/%d // Sometime rgb:%d/%d/%d should be encoded into the 0..65535 range, so #%x%x%x is more reliable setCursorColorRgb: { on: '\x1b]12;#%x%x%x\x07' } , // it want rgb as parameter, like rgb:127/0/32 setDefaultColorRgb: { on: '\x1b]10;#%x%x%x\x07' } , // ->|TODOC|<- not widely supported setDefaultBgColorRgb: { on: '\x1b]11;#%x%x%x\x07' } , // ->|TODOC|<- not widely supported setColorLL: { on: '\x1b]4;%u;#%x%x%x\x07' } , setFont: { on: '\x1b]50;%s\x07' } , // ->|TODOC|<- rarely supported } ; /* Inputs management */ var handler = {} ; handler.mouseX11Protocol = function mouseX11Protocol( basename , buffer ) { var code = buffer[ 0 ] ; var result = { data: { shift: code & 4 ? true : false , alt: code & 8 ? true : false , ctrl: code & 16 ? true : false } } ; if ( code & 32 ) { if ( code & 64 ) { result.name = basename + ( code & 1 ? '_WHEEL_DOWN' : '_WHEEL_UP' ) ; } else { // Button event switch ( code & 3 ) { case 0 : result.name = basename + '_LEFT_BUTTON_PRESSED' ; break ; case 1 : result.name = basename + '_MIDDLE_BUTTON_PRESSED' ; break ; case 2 : result.name = basename + '_RIGHT_BUTTON_PRESSED' ; break ; case 3 : result.name = basename + '_BUTTON_RELEASED' ; break ; } } } else if ( code & 64 ) { // Motion event result.name = basename + '_MOTION' ; } result.eaten = 3 ; result.data.code = code ; result.data.x = buffer[ 1 ] - 32 ; result.data.y = buffer[ 2 ] - 32 ; return result ; } ; handler.mouseSGRProtocol = function mouseSGRProtocol( basename , buffer ) { var code , pressed , matches , result ; matches = buffer.toString().match( /^([0-9]*);([0-9]*);([0-9]*)(.)/ ) ; code = parseInt( matches[ 1 ] ) ; pressed = matches[ 4 ] !== 'm' ; result = { data: { shift: code & 4 ? true : false , alt: code & 8 ? true : false , ctrl: code & 16 ? true : false } } ; result.data.x = parseInt( matches[ 2 ] ) ; result.data.y = parseInt( matches[ 3 ] ) ; result.eaten = matches[ 0 ].length ; if ( code & 32 ) { // Motions event result.name = basename + '_MOTION' ; } else { if ( code & 64 ) { result.name = basename + ( code & 1 ? '_WHEEL_DOWN' : '_WHEEL_UP' ) ; } else { // Button event switch ( code & 3 ) { case 0 : result.name = basename + '_LEFT_BUTTON' ; //if ( this.state.button.left === pressed ) { result.disable = true ; } this.state.button.left = pressed ; break ; case 1 : result.name = basename + '_MIDDLE_BUTTON' ; //if ( this.state.button.middle === pressed ) { result.disable = true ; } this.state.button.middle = pressed ; break ; case 2 : result.name = basename + '_RIGHT_BUTTON' ; //if ( this.state.button.right === pressed ) { result.disable = true ; } this.state.button.right = pressed ; break ; case 3 : result.name = basename + '_OTHER_BUTTON' ; //if ( this.state.button.other === pressed ) { result.disable = true ; } this.state.button.other = pressed ; break ; } result.name += pressed ? '_PRESSED' : '_RELEASED' ; } } result.data.code = code ; return result ; } ; handler.cursorLocation = function cursorLocation( basename , paramString ) { var params = paramString.split( ';' ) ; return { name: 'CURSOR_LOCATION' , data: { x: parseInt( params[ 1 ] ) , y: parseInt( params[ 0 ] ) } } ; } ; handler.colorRegister = function colorRegister( basename , paramString ) { var matches = paramString.match( /^([0-9]*);rgb:([0-9a-f]{2})[0-9a-f]*\/([0-9a-f]{2})[0-9a-f]*\/([0-9a-f]{2})[0-9a-f]*/ ) ; return { name: 'COLOR_REGISTER' , data: { register: parseInt( matches[ 1 ] ) , r: parseInt( matches[ 2 ] , 16 ) , g: parseInt( matches[ 3 ] , 16 ) , b: parseInt( matches[ 4 ] , 16 ) } } ; } ; handler.screenSize = function screenSize( basename , paramString ) { var params = paramString.split( ';' ) , width = parseInt( params[ 1 ] ) , height = parseInt( params[ 0 ] ) , resized = this.root.width !== width || this.root.height !== height ; this.root.width = width ; this.root.height = height ; return { name: 'SCREEN_SIZE' , data: { resized: resized , width: width , height: height } } ; } ; /* Key Mapping */ var keymap = { // Application Keypad KP_NUMLOCK: [] , // '\x1bOP' , KP_DIVIDE: '\x1bOo' , KP_MULTIPLY: '\x1bOj' , KP_MINUS: '\x1bOm' , KP_0: [] , // '\x1b[2~' , KP_1: [] , // '\x1bOF' , KP_2: [] , // '\x1b[B' , KP_3: [] , // '\x1b[6~' , KP_4: [] , // '\x1b[D' , KP_5: [ '\x1bOE' , '\x1b[E' ] , KP_6: [] , // '\x1b[C' , KP_7: [] , // '\x1bOH' , KP_8: [] , // '\x1b[A' , KP_9: [] , // '\x1b[5~' , KP_PLUS: '\x1bOk' , KP_DELETE: [] , // '\x1b[3~' , KP_ENTER: '\x1bOM' , CURSOR_LOCATION: { starter: '\x1b[' , ender: 'R' , event: 'terminal' , handler: 'cursorLocation' } , SCREEN_SIZE: { starter: '\x1b[8;' , ender: 't' , event: 'terminal' , handler: 'screenSize' } , COLOR_REGISTER: { starter: '\x1b]4;' , ender: '\x07' , event: 'terminal' , handler: 'colorRegister' } , FOCUS_IN: { code: '\x1b[I' , event: 'terminal' , data: {} } , FOCUS_OUT: { code: '\x1b[O' , event: 'terminal' , data: {} } , MOUSE: [ { code: '\x1b[<' , event: 'mouse' , handler: 'mouseSGRProtocol' } , { code: '\x1b[M' , event: 'mouse' , handler: 'mouseX11Protocol' } ] } ; module.exports = { esc: esc , keymap: keymap , handler: handler , colorRegister: require( '../colorScheme/xterm.json' ) } ;