// Copyright (C) 2013-2014 ChaosForge Ltd // http://chaosforge.org/ // // This file is part of NV Libraries. // For conditions of distribution and use, see copyright notice in nv.hh #include "nv/curses/curses_terminal.hh" #include "nv/core/time.hh" #include "nv/lib/curses.hh" using namespace nv; curses_terminal::curses_terminal( dimension size ) : terminal( size ) { load_curses_library(); m_screen = initscr(); raw(); cbreak(); noecho(); nodelay ( (WINDOW*)m_screen, true ); intrflush( (WINDOW*)m_screen, false ); keypad ( (WINDOW*)m_screen, true ); start_color(); resize_term( size.y, size.x ); PDC_save_key_modifiers( true ); init_pair( 1, 0, 0 ); init_pair( 2, 1, 0 ); init_pair( 3, 2, 0 ); init_pair( 4, 3, 0 ); init_pair( 5, 4, 0 ); init_pair( 6, 5, 0 ); init_pair( 7, 6, 0 ); init_pair( 8, 7, 0 ); clear(); refresh(); curs_set(1); m_update_needed = false; } void curses_terminal::update() { if (m_update_needed) { refresh(); m_update_needed = false; } } void curses_terminal::print( position p, uint32 color, unsigned char ch ) { m_update_needed = true; if ( color > 7 ) { attrset((static_cast(color-7) << 24) & 0xff000000ul | 0x00800000ul); } else { attrset((static_cast(color+1) << 24) & 0xff000000ul); } mvaddch( p.y-1, p.x-1, ch ); move( m_cursor.y-1, m_cursor.x-1 ); } void curses_terminal::clear( rectangle r ) { attrset( 0x00000000ul | 0x00800000ul ); for ( int x = r.ul.x-1; x <= r.lr.x-1; ++x ) for ( int y = r.ul.y-1; y <= r.lr.y-1; ++y ) mvaddch( y, x, ' ' ); } void curses_terminal::clear() { m_update_needed = true; ::clear(); move( m_cursor.y-1, m_cursor.x-1 ); } bool curses_terminal::poll( io_event& kevent ) { // Sleep so we don't get 100% processor usage sleep(10); // Get value from curses int result = wgetch((WINDOW*)m_screen); // If value is err, return none event if ( result == -1 ) { return false; } // Zero the fields kevent.type = EV_KEY; kevent.key.pressed = true; kevent.key.ascii = 0; kevent.key.code = nv::KEY_NONE; kevent.key.control = false; kevent.key.shift = false; // if result is a typable char place it into the structure if ( result >= 32 && result < 128 ) { kevent.key.ascii = static_cast(result); } // Check the control and shift states // TODO: obviously there is an ERROR here :P kevent.key.control = (PDC_get_key_modifiers() & 2) != 0; kevent.key.shift = (PDC_get_key_modifiers() & 2) != 0; // if result is a typable char from the directly transformable ranges if ( (result >= nv::KEY_A && result <= nv::KEY_Z) || (result >= nv::KEY_0 && result <= nv::KEY_9) || result == ' ' ) { kevent.key.code = static_cast(result); } // if result is a typable char from the a..z range if ( result >= nv::KEY_A + 32 && result <= nv::KEY_Z + 32 ) { kevent.key.code = static_cast(result - 32); } // if result is a typable char from the 0..9 range if ( result >= nv::KEY_0 && result <= nv::KEY_9 ) { kevent.key.code = static_cast(result); } // other recognized codes switch ( result ) { case 8 : kevent.key.code = nv::KEY_BACK; break; case 9 : kevent.key.code = nv::KEY_TAB; break; case 13 : kevent.key.code = nv::KEY_ENTER; break; case 27 : kevent.key.code = nv::KEY_ESCAPE; break; case 0x103 : kevent.key.code = nv::KEY_UP; break; case 0x102 : kevent.key.code = nv::KEY_DOWN; break; case 0x104 : kevent.key.code = nv::KEY_LEFT; break; case 0x105 : kevent.key.code = nv::KEY_RIGHT; break; case 0x153 : kevent.key.code = nv::KEY_PGUP; break; case 0x152 : kevent.key.code = nv::KEY_PGDOWN; break; case 0x106 : kevent.key.code = nv::KEY_HOME; break; case 0x166 : kevent.key.code = nv::KEY_END; break; } // If key was understood by nv, then it's valid, otherwise ignored return kevent.key.ascii != 0 || kevent.key.code != 0; } void curses_terminal::set_cursor( position p ) { terminal::set_cursor( p ); move( m_cursor.y-1, m_cursor.x-1 ); } void curses_terminal::show_cursor() { curs_set(1); } void curses_terminal::hide_cursor() { curs_set(0); } curses_terminal::~curses_terminal() { endwin(); }