func (cw *chatWin) handleInput(win *goncurses.Window) (line string) { k := win.GetChar() if k == 0 { return "" } // some systems send a DEL ASCII character instead of KEY_BACKSPACE // account for both just in case if k == 127 { k = goncurses.KEY_BACKSPACE } switch k { case goncurses.KEY_TAB: // tab // case goncurses.KEY_RETURN: // enter key vs. KEY_ENTER case goncurses.KEY_DOWN: // down arrow key case goncurses.KEY_UP: // up arrow key case goncurses.KEY_LEFT: // left arrow key case goncurses.KEY_RIGHT: // right arrow key case goncurses.KEY_HOME: // home key case goncurses.KEY_BACKSPACE: // backpace if len(cw.line) > 0 { cw.line = cw.line[:len(cw.line)-1] } y, x := win.CursorYX() // TODO: handle this more elegantly (e.g. tell ncurses not to print backspaces) // we have to do this three times because ncurses inserts two characters for backspace // this is likely wrong in some cases for i := 0; i < 3; i++ { y, x = cw.moveLeft(y, x) win.MoveDelChar(y, x) } win.Refresh() case goncurses.KEY_F1: // F1 key case goncurses.KEY_F2: // F2 key case goncurses.KEY_F3: // F3 key case goncurses.KEY_F4: // F4 key case goncurses.KEY_F5: // F5 key case goncurses.KEY_F6: // F6 key case goncurses.KEY_F7: // F7 key case goncurses.KEY_F8: // F8 key case goncurses.KEY_F9: // F9 key case goncurses.KEY_F10: // F10 key case goncurses.KEY_F11: // F11 key case goncurses.KEY_F12: // F12 key case goncurses.KEY_DL: // delete-line key case goncurses.KEY_IL: // insert-line key case goncurses.KEY_DC: // delete-character key case goncurses.KEY_IC: // insert-character key case goncurses.KEY_EIC: // sent by rmir or smir in insert mode case goncurses.KEY_CLEAR: // clear-screen or erase key3 case goncurses.KEY_EOS: // clear-to-end-of-screen key case goncurses.KEY_EOL: // clear-to-end-of-line key case goncurses.KEY_SF: // scroll-forward key case goncurses.KEY_SR: // scroll-backward key case goncurses.KEY_PAGEDOWN: // page-down key (next-page) case goncurses.KEY_PAGEUP: // page-up key (prev-page) case goncurses.KEY_STAB: // set-tab key case goncurses.KEY_CTAB: // clear-tab key case goncurses.KEY_CATAB: // clear-all-tabs key case goncurses.KEY_RETURN: // enter key vs. KEY_ENTER fallthrough case goncurses.KEY_ENTER: // enter/send key line = cw.line cw.line = "" win.Erase() win.Print(PROMPT) case goncurses.KEY_PRINT: // print key case goncurses.KEY_LL: // lower-left key (home down) case goncurses.KEY_A1: // upper left of keypad case goncurses.KEY_A3: // upper right of keypad case goncurses.KEY_B2: // center of keypad case goncurses.KEY_C1: // lower left of keypad case goncurses.KEY_C3: // lower right of keypad case goncurses.KEY_BTAB: // back-tab key case goncurses.KEY_BEG: // begin key case goncurses.KEY_CANCEL: // cancel key case goncurses.KEY_CLOSE: // close key case goncurses.KEY_COMMAND: // command key case goncurses.KEY_COPY: // copy key case goncurses.KEY_CREATE: // create key case goncurses.KEY_END: // end key case goncurses.KEY_EXIT: // exit key case goncurses.KEY_FIND: // find key case goncurses.KEY_HELP: // help key case goncurses.KEY_MARK: // mark key case goncurses.KEY_MESSAGE: // message key case goncurses.KEY_MOVE: // move key case goncurses.KEY_NEXT: // next key case goncurses.KEY_OPEN: // open key case goncurses.KEY_OPTIONS: // options key case goncurses.KEY_PREVIOUS: // previous key case goncurses.KEY_REDO: // redo key case goncurses.KEY_REFERENCE: // reference key case goncurses.KEY_REFRESH: // refresh key case goncurses.KEY_REPLACE: // replace key case goncurses.KEY_RESTART: // restart key case goncurses.KEY_RESUME: // resume key case goncurses.KEY_SAVE: // save key case goncurses.KEY_SBEG: // shifted begin key case goncurses.KEY_SCANCEL: // shifted cancel key case goncurses.KEY_SCOMMAND: // shifted command key case goncurses.KEY_SCOPY: // shifted copy key case goncurses.KEY_SCREATE: // shifted create key case goncurses.KEY_SDC: // shifted delete-character key case goncurses.KEY_SDL: // shifted delete-line key case goncurses.KEY_SELECT: // select key case goncurses.KEY_SEND: // shifted end key case goncurses.KEY_SEOL: // shifted clear-to-end-of-line key case goncurses.KEY_SEXIT: // shifted exit key case goncurses.KEY_SFIND: // shifted find key case goncurses.KEY_SHELP: // shifted help key case goncurses.KEY_SHOME: // shifted home key case goncurses.KEY_SIC: // shifted insert-character key case goncurses.KEY_SLEFT: // shifted left-arrow key case goncurses.KEY_SMESSAGE: // shifted message key case goncurses.KEY_SMOVE: // shifted move key case goncurses.KEY_SNEXT: // shifted next key case goncurses.KEY_SOPTIONS: // shifted options key case goncurses.KEY_SPREVIOUS: // shifted previous key case goncurses.KEY_SPRINT: // shifted print key case goncurses.KEY_SREDO: // shifted redo key case goncurses.KEY_SREPLACE: // shifted replace key case goncurses.KEY_SRIGHT: // shifted right-arrow key case goncurses.KEY_SRSUME: // shifted resume key case goncurses.KEY_SSAVE: // shifted save key case goncurses.KEY_SSUSPEND: // shifted suspend key case goncurses.KEY_SUNDO: // shifted undo key case goncurses.KEY_SUSPEND: // suspend key case goncurses.KEY_UNDO: // undo key case goncurses.KEY_MOUSE: // any mouse event case goncurses.KEY_RESIZE: // Terminal resize event //case goncurses.KEY_EVENT: // We were interrupted by an event case goncurses.KEY_MAX: default: cw.line += goncurses.KeyString(k) } return }
// handles keyboard input func inputHandler(inputWin *gc.Window, stdscr *gc.Window, contactsMenuWin *gc.Window, contactMenu *gc.Menu, msgWin *gc.Window) { var NLlocate = map[int]newLine{} var c gc.Char var rawInput gc.Key max_y, max_x := inputWin.MaxYX() for { rawInput = inputWin.GetChar() c = gc.Char(rawInput) // debugLog.Println(rawInput) // debugLog.Println(c) //Escape to Quit if c == gc.Char(27) { break } else if rawInput == gc.KEY_BACKSPACE || c == gc.Char(127) { //Delete Key y, x := inputWin.CursorYX() var del = byte('F') if x != 0 { inputWin.MoveDelChar(y, x-1) del = inputBuffer[placer] copy(inputBuffer[placer:len(inputBuffer)-1], inputBuffer[placer+1:]) inputBuffer = inputBuffer[0 : len(inputBuffer)-1] placer-- if del != byte('\n') && NLlocate[y+scroll]._cursorX > x { temp := newLine{NLlocate[y+scroll]._cursorX - 1, NLlocate[y+scroll]._placer - 1} NLlocate[y+scroll] = temp } //debugLog.Println(inputBuffer) } else if y != 0 { //when x==0 and y!=0 inputWin.Move(y-1, max_x-1) inputWin.MoveDelChar(y-1, max_x-1) del = inputBuffer[placer] copy(inputBuffer[placer:len(inputBuffer)-1], inputBuffer[placer+1:]) inputBuffer = inputBuffer[0 : len(inputBuffer)-1] //debugLog.Println(inputBuffer) placer-- } if del == byte('\n') { inputWin.Erase() inputWin.Print(string(inputBuffer)) inputWin.Move(y-1, NLlocate[y-1+scroll]._cursorX) temp, check := NLlocate[y+scroll] var temp_cursor = temp._cursorX var temp_placer = temp._placer if check && NLlocate[y-1+scroll]._cursorX+temp_cursor >= max_x { _newLine := newLine{NLlocate[y-1+scroll]._cursorX + temp_cursor - max_x, NLlocate[y+scroll]._placer - 1} NLlocate[y+scroll] = _newLine delete(NLlocate, y-1) } else if check { // check if there are any '\n' this line var largest = -1 // if yes, select all '\n' and move for i := range NLlocate { // placer by 1 and adjust cursor if i >= y+scroll { // accordingly if next_nl, ok := NLlocate[i+1]; ok { new_nl := newLine{next_nl._cursorX, next_nl._placer - 1} NLlocate[i] = new_nl } } if i > largest { largest = i } } delete(NLlocate, largest) // delete last map entry _newLine := newLine{NLlocate[y-1+scroll]._cursorX + temp_cursor, NLlocate[y-1+scroll]._placer + temp_placer - 1} NLlocate[y-1+scroll] = _newLine } else { delete(NLlocate, y-1+scroll) } } } else if c == gc.KEY_PAGEDOWN { //debugLog.Println("HIT DOWN") msgWin.Scroll(-10) msgWin.Refresh() inputWin.Refresh() } else if c == gc.KEY_PAGEUP { //debugLog.Println("HIT UP") msgWin.Scroll(10) msgWin.Refresh() inputWin.Refresh() } else if c == gc.KEY_LEFT { y, x := inputWin.CursorYX() if x != 0 { inputWin.Move(y, x-1) placer-- } else if y != 0 { inputWin.Move(y-1, max_x-1) placer-- } if len(inputBuffer) > 0 && inputBuffer[placer+1] == byte('\n') { inputWin.Move(y-1, NLlocate[y-1+scroll]._cursorX) } } else if c == gc.KEY_RIGHT { y, x := inputWin.CursorYX() placer++ if inputBuffer == nil || placer == len(inputBuffer) { inputBuffer = append(inputBuffer, byte(' ')) } if inputBuffer[placer] == byte('\n') || x >= max_x-1 { inputWin.Move(y+1, 0) } else { inputWin.Move(y, x+1) } } else if c == gc.KEY_UP { y, x := inputWin.CursorYX() if y == 0 && placer == 0 { continue } else if y == 0 && scroll > 0 { inputWin.Move(0, x) inputWin.Scroll(-1) scroll -= 1 if NLlocate[y-2+scroll]._placer != 0 { inputWin.Erase() inputWin.Print(string(inputBuffer[(NLlocate[y-2+scroll]._placer):])) } else if placer-max_x-x > 0 { inputWin.Erase() inputWin.Print(string(inputBuffer[(placer - x - max_x):])) } else { inputWin.Erase() inputWin.Print(string(inputBuffer)) } } if y != 0 { inputWin.Move(y-1, x) placer -= max_x if placer < 0 { placer = 0 } } if NLlocate[y-1+scroll]._placer != 0 { if NLlocate[y-1+scroll]._cursorX < x { placer = NLlocate[y-1+scroll]._placer inputWin.Move(y-1, NLlocate[y-1+scroll]._cursorX) } else { placer = NLlocate[y-1+scroll]._placer - (NLlocate[y-1+scroll]._cursorX - x) } } } else if c == gc.KEY_DOWN { y, x := inputWin.CursorYX() if y != max_y { inputWin.Move(y+1, x) if NLlocate[y+scroll]._placer == 0 { placer += max_x } else { placer = NLlocate[y+scroll]._placer + x + 1 } } else if y == max_y { inputWin.Scroll(1) scroll += 1 inputWin.Move(max_y-1, x) if NLlocate[y+scroll]._placer == 0 { placer += max_x } else { placer = NLlocate[y+scroll]._placer + x + 1 } } if placer >= len(inputBuffer) { for i := len(inputBuffer); i < placer+1; i++ { inputBuffer = append(inputBuffer, byte(' ')) } } } else if rawInput == gc.KEY_TAB { y, x := inputWin.CursorYX() gc.Cursor(0) escapeHandler := contactsWindowNavigation(contactsMenuWin, contactMenu) if escapeHandler == 1 { return } gc.Cursor(1) inputWin.Move(y, x) } else if rawInput == gc.KEY_RETURN { placer = -1 for i := range NLlocate { delete(NLlocate, i) } sendMsg(inputWin, globalMsgWin) } else if rawInput == gc.KEY_SRIGHT { y, x := inputWin.CursorYX() if inputBuffer == nil || placer == len(inputBuffer)-1 { if y == max_y-1 { scroll++ } inputWin.Print("\n") temp := newLine{x, placer} NLlocate[y+scroll] = temp placer++ inputBuffer = append(inputBuffer, byte('\n')) } else { inputWin.Erase() inputBuffer = append(inputBuffer, byte('\n')) copy(inputBuffer[placer+1:], inputBuffer[placer:]) inputBuffer[placer+1] = byte('\n') inputWin.Print(string(inputBuffer)) temp := newLine{x, placer} placer++ nextholder, check := NLlocate[y+1+scroll] if check { for i := range NLlocate { if i == y+scroll { _newLine := newLine{NLlocate[i]._cursorX + 1 - x, NLlocate[i]._placer + 1} nextholder := NLlocate[i+1] _ = nextholder NLlocate[i+1] = _newLine } else if i > y { temp := NLlocate[i+1] NLlocate[i+1] = nextholder nextholder = temp } } } NLlocate[y+scroll] = temp inputWin.Move(y+1, 0) } } else if rawInput == gc.KEY_SLEFT { } else { y, x := inputWin.CursorYX() if inputBuffer == nil || placer == len(inputBuffer)-1 { inputWin.Print(string(c)) inputBuffer = append(inputBuffer, byte(c)) } else { inputWin.Erase() inputBuffer = append(inputBuffer, byte(c)) copy(inputBuffer[placer+1:], inputBuffer[placer:]) inputBuffer[placer+1] = byte(c) inputWin.Print(string(inputBuffer)) for i := range NLlocate { if i > y+scroll { tempLine := newLine{NLlocate[i]._cursorX, NLlocate[i]._placer + 1} NLlocate[i] = tempLine } } if NLlocate[y+scroll]._cursorX >= x { if NLlocate[y+scroll]._cursorX == max_x { copy(inputBuffer[NLlocate[y+scroll]._placer:len(inputBuffer)-1], inputBuffer[NLlocate[y+scroll]._placer+1:]) inputBuffer = inputBuffer[0 : len(inputBuffer)-1] delete(NLlocate, y) } else { temp := newLine{NLlocate[y+scroll]._cursorX + 1, NLlocate[y+scroll]._placer + 1} NLlocate[y+scroll] = temp } } } placer++ inputWin.Move(y, x+1) } } }