Onscreen QWERTY keypad for RA8857 based display. Uses the resistive touch panel.

Dependents:   RA8875_KeyPadDemo PUB_RA8875_Keypad IAC_Final_Monil_copy

Keypad.cpp

Committer:
WiredHome
Date:
2016-03-05
Revision:
2:6d05764dfde7
Parent:
1:7feeebbd8367
Child:
3:402f1126a3ec

File content as of revision 2:6d05764dfde7:

#include "Keypad.h"

// byte pairs: size, symbol [,size, symbol [, size, symbol [...]]]
// size is a scale factor where 10 = "normal calculated size" based on the keyboard width and the # of keys, 5 is 1/2 width, etc.
// symbol is either the ASCII character to show, when leveraging the RA8875 internal fonts, or it is a special
//    character [normally non-printable] that is intercepted to perform an operation (e.g. <bs>, <shift>, etc.)
//    \x01: special no-key value, to leave whitespace before the next key.
const char kpd_shiftkeys[] = {
    5,'\x01', 8,'\x15',10,'~',10,'!',10,'@',10,'#',10,'$',10,'%',10,'^',10,'&',10,'*',10,'(',10,')',10,'_',   10,'+',10,'\x1B',0,0,
    5,'\x01',12,'\x1A',10,'Q',10,'W',10,'E',10,'R',10,'T',10,'Y',10,'U',10,'I',10,'O',10,'P',10,'{',   10,'}',10,'|',0,0,
    5,'\x01',15,' ',10,'A',10,'S',10,'D',10,'F',10,'G',10,'H',10,'J',10,'K',10,'L',10,':',10,'"',   17,'\x1C',0,0,
    5,'\x01',21,'\x18',10,'Z',10,'X',10,'C',10,'V',10,'B',10,'N',10,'M',10,'<',10,'>',10,'?',21,'\x18',0,0,
    5,'\x01',40,'\x01',55,' ',0,0,
    0,0
};
const char kpd_unshiftkeys[] = {
    5,'\x01', 8,'\x15',10,'`',10,'1',10,'2',10,'3',10,'4',10,'5',10,'6',10,'7',10,'8',10,'9',10,'0',10,'-',   10,'=',10,'\x1B',0,0,
    5,'\x01',12,'\x1A',10,'q',10,'w',10,'e',10,'r',10,'t',10,'y',10,'u',10,'i',10,'o',10,'p',10,'[',   10,']',10,'\\',0,0,
    5,'\x01',15,' ',10,'a',10,'s',10,'d',10,'f',10,'g',10,'h',10,'j',10,'k',10,'l',10,';',10,'\'',  17,'\x1C',0,0,
    5,'\x01',21,'\x18',10,'z',10,'x',10,'c',10,'v',10,'b',10,'n',10,'m',10,',',10,'.',10,'/',21,'\x18',0,0,
    5,'\x01',40,'\x01',55,' ',0,0,
    0,0
};

const Keypad::keyboard_t internalkbd = {
    0,-1,   // x,y: 0; start at left edge, -1; top is calculated from # rows
         //      -1 is size calculated
    0,      // wi,h: width is calculated
    0,      //      bottom of screen justified
    5,      // 5 rows
    15,     // columns in the <esc>`1234...-=<bs> row
    kpd_unshiftkeys,
    kpd_shiftkeys
};



Keypad::Keypad(RA8875 & _ra, color_t _fore, color_t _back) : ra(_ra), fore(_fore), back(_back) {
    shift = false;
    enter_key = KYBD_SYM_ENTER;
    esc_key   = KYBD_SYM_ESCAPE;
}

Keypad::~Keypad() {
}

bool Keypad::SetKeyboard(const keyboard_t * _kbd, char _enter_key, char _esc_key) {
    if (_kbd)
        kbd = _kbd;
    else
        kbd = &internalkbd;
    enter_key = _enter_key;
    esc_key   = _esc_key;
    return true;
}

void Keypad::DrawKey(rect_t r, char c, bool invert) {
    ra.fillroundrect(r, 2, 2, invert ? fore : back);
    ra.roundrect(r, 2, 2, invert ? back : fore);
    ra.SetTextCursor(r.p1.x+(r.p2.x-r.p1.x)/2-ra.fontwidth()/2, r.p1.y+2);
    if (invert) {
        ra.foreground(back);
        ra.background(fore);
    }
    ra.putc(c);
    if (invert) {
        ra.foreground(fore);
        ra.background(back);
    }
}

void Keypad::Erase(color_t c) {
    dim_t kH = ra.fontheight() + 4;
    rect_t r = ComputeKeypadRect();
    
    ra.fillrect(r, c);    
}

void Keypad::DrawInputPanel(const char * prompt) {
    dim_t kH = ra.fontheight() + 4;
    rect_t r = ComputeKeypadRect();

    ra.fillrect(r, back);
    ra.foreground(fore);
    ra.background(back);
    ra.SetTextCursor(r.p1.x,r.p1.y+2);
    ra.puts(prompt);
    userText = ra.GetTextCursor();
    DrawKeypad();
}

rect_t Keypad::ComputeKeypadRect(void) {
    dim_t kH = ra.fontheight() + 4;
    rect_t r;
    
    if (kbd->x <= 0)
        r.p1.x = 0;
    else
        r.p1.x = kbd->x;
    if (kbd->y <= 0)
        r.p1.y = ra.height() - (kH * (kbd->rows+1)) - 1;
    else
        r.p1.y = kbd->y;
    if (kbd->width == 0)
        r.p2.x = ra.width() - 1;
    else
        r.p2.x = r.p1.x + kbd->width - 1;
    if (kbd->height == 0)
        r.p2.y = ra.height() - 1;   
    else
        r.p2.y = r.p1.y + kbd->height - 1;
    printf("KeypadRect (%d,%d) - (%d,%d)\r\n", r.p1.x, r.p1.y, r.p2.x, r.p2.y);
    return r; 
}

void Keypad::DrawKeypad(void) {
    dim_t fW = ra.fontwidth();
    dim_t fH = ra.fontheight();
    dim_t kW;
    dim_t kH = fH + 4;
    
    const char * p = kbd->keydef1;
    rect_t r = ComputeKeypadRect();
    rect_t ref = r;
    kW = (ref.p2.x - ref.p1.x) / (kbd->cols+1);
    printf("DrawKeypad kW=%d from (%d,%d) %d\r\n", kW, ref.p2.x, ref.p1.x, kbd->cols+1);
    r.p1.y += kH;
    if (shift)
        p = kbd->keydef2;
    while (*p || *(p+2)) {
        if (*p == 0) {
            r.p1.x = ref.p1.x;
            r.p1.y += kH;
        } else {
            const char * symbol = p + 1;
            if (*symbol >= 0x10) {
                r.p2.x = r.p1.x + (kW * *p)/10;
                r.p2.y = r.p1.y + kH;
                DrawKey(r,*symbol);
            }
            r.p1.x += (kW * *p)/10;
        }
        p+=2;
    }
}

char Keypad::isKeyTouched(point_t * point, rect_t * rectTouched) {
    dim_t kW;
    dim_t kH = ra.fontheight() + 4;
    
    const char * p = kbd->keydef1;
    rect_t r = ComputeKeypadRect();
    rect_t ref = r;
    kW = (ref.p2.x - ref.p1.x) / (kbd->cols+1);
    r.p1.y = r.p1.y + kH;    
    if (shift)
        p = kbd->keydef2;
    while (*p || *(p+2)) {
        if (*p == 0) {
            r.p1.x = ref.p1.x;
            r.p1.y += kH;
        } else {
            const char * symbol = p + 1;
            if (*symbol >= 0x10) {
                r.p2.x = r.p1.x + (kW * *p)/10;
                r.p2.y = r.p1.y + kH;
                if (ra.Intersect(r, *point)) {
                    if (rectTouched)
                        *rectTouched = r;
                    return (*symbol);
                }
            }
            r.p1.x += (kW * *p)/10;
        }
        p+=2;
    }
    return 0;
}

void Keypad::ShowBufferMetrics(void) {
    rect_t r = ComputeKeypadRect();
    ra.SetTextCursor(r.p2.x-1-ra.fontwidth()*7, r.p1.y+2);
    ra.printf("%03d/%03d", pNext - pStart, bufSize);            // "001/100"
    //ra.SetTextCursor(ra.width()-1-ra.fontwidth()*7, ra.height()-1-ra.fontheight());
    ra.SetTextCursor(userText.x, userText.y);
    ra.SetTextCursorControl(RA8875::UNDER);
}

bool Keypad::GetString(char * buffer, size_t size, const char * prompt, char mask) {
    point_t point = {0, 0};

    pStart = pNext = buffer;
    bufSize = size;
    DrawInputPanel(prompt);
    ShowBufferMetrics();
    while (1) {
        if (touch == ra.TouchPanelReadable(&point)) {
            rect_t touchRect;
            // find out if they touched a key;
            char key = isKeyTouched(&point, &touchRect);
            if (key) {
                DrawKey(touchRect, key, true);
                wait_ms(50);
                TouchCode_t is;
                do {
                    is = ra.TouchPanelReadable(NULL);
                    //printf("is: %d\r\n", is);
                } while (is != no_touch);
                DrawKey(touchRect, key);
            }
            printf("Touch %02X at (%d,%d)\r\n", key, point.x, point.y);
            if (key == enter_key) {
                *pNext = '\0';
                ra.SetTextCursorControl();
                return true;
            } else if (key == esc_key) {
                *buffer = '\0';
                ra.SetTextCursorControl();
                return false;
            } else if (key == KYBD_SYM_BS) {
                if (pNext > buffer) {
                    pNext--;
                    // blank the last char
                    userText.x -= ra.fontwidth();
                    ra.SetTextCursor(userText.x, userText.y);
                    ra.putc(' ');
                }
            } else if (key == KYBD_SYM_TAB) {
                *pNext++ = ' ';
                ra.SetTextCursor(userText.x, userText.y);
                ra.putc(' ');
                userText.x += ra.fontwidth();
            } else if (key == KYBD_SYM_SHIFT) {
                shift = !shift;
                DrawKeypad();
            } else if (key) {
                *pNext++ = key;
                ra.SetTextCursor(userText.x, userText.y);
                if (mask)
                    ra.putc(mask);
                else
                    ra.putc(key);
                userText.x += ra.fontwidth();
            }
            if ((pNext - buffer) >= (size - 1)) {
                *pNext = '\0';
                ra.SetTextCursorControl();
                return true;
            }
            ShowBufferMetrics();
        }
    }
}

const Keypad::keyboard_t * Keypad::GetInternalKeypad(void) {
    return &internalkbd;
}