232 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			232 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * This file is part of MultiROM.
 | 
						|
 *
 | 
						|
 * MultiROM is free software: you can redistribute it and/or modify
 | 
						|
 * it under the terms of the GNU General Public License as published by
 | 
						|
 * the Free Software Foundation, either version 3 of the License, or
 | 
						|
 * (at your option) any later version.
 | 
						|
 *
 | 
						|
 * MultiROM is distributed in the hope that it will be useful,
 | 
						|
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
 * GNU General Public License for more details.
 | 
						|
 *
 | 
						|
 * You should have received a copy of the GNU General Public License
 | 
						|
 * along with MultiROM.  If not, see <http://www.gnu.org/licenses/>.
 | 
						|
 */
 | 
						|
 | 
						|
#include <stdlib.h>
 | 
						|
 | 
						|
#include "containers.h"
 | 
						|
#include "keyboard.h"
 | 
						|
#include "util.h"
 | 
						|
#include "log.h"
 | 
						|
#include "workers.h"
 | 
						|
 | 
						|
#define KS(x) ((x-1) << 16)
 | 
						|
#define GET_KS(x) ((x & 0xFF0000)>> 16)
 | 
						|
 | 
						|
#define KF(x) ((x) << 8)
 | 
						|
#define GET_KF(x) ((x & 0xFF00) >> 8)
 | 
						|
#define KFLAG_HALF KF(0x01)
 | 
						|
#define KFLAG_PLUS_HALF KF(0x02)
 | 
						|
 | 
						|
static const char *specialKeys[] = {
 | 
						|
    NULL,  // OSK_EMPTY
 | 
						|
    "OK",  // OSK_ENTER
 | 
						|
    "<",   // OSK_BACKSPACE
 | 
						|
    "X",   // OSK_CLEAR
 | 
						|
    "abc", // OSK_CHARSET1
 | 
						|
    "ABC", // OSK_CHARSET2
 | 
						|
    "?123",// OSK_CHARSET3
 | 
						|
    "=\\<",// OSK_CHARSET4
 | 
						|
};
 | 
						|
 | 
						|
// One keycode
 | 
						|
// bits | 0         | 8       | 16      |
 | 
						|
// data | character | flags   | colspan |
 | 
						|
static const uint32_t pinKeycodeMap[] = {
 | 
						|
    OSK_EMPTY | KFLAG_HALF, '1', '2', '3', OSK_EMPTY,
 | 
						|
    OSK_EMPTY | KFLAG_HALF, '4', '5', '6', OSK_CLEAR,
 | 
						|
    OSK_EMPTY | KFLAG_HALF, '7', '8', '9', OSK_BACKSPACE,
 | 
						|
    OSK_EMPTY | KFLAG_HALF, '0' | KS(3),   OSK_ENTER,
 | 
						|
    0
 | 
						|
};
 | 
						|
 | 
						|
// rows, cols
 | 
						|
static const uint32_t pinKeycodeMapDimensions[] = { 4, 5 };
 | 
						|
 | 
						|
static const uint32_t normalKeycodeMapCharset1[] = {
 | 
						|
    'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p',
 | 
						|
    OSK_EMPTY| KFLAG_HALF, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l',
 | 
						|
    OSK_CHARSET2 | KFLAG_PLUS_HALF, 'z', 'x', 'c', 'v', 'b', 'n', 'm', OSK_BACKSPACE | KFLAG_PLUS_HALF, OSK_EMPTY,
 | 
						|
    OSK_CHARSET3 | KS(2), ' ' | KS(5), '.', OSK_ENTER | KS(2),
 | 
						|
    0
 | 
						|
};
 | 
						|
 | 
						|
static const uint32_t normalKeycodeMapCharset2[] = {
 | 
						|
    'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P',
 | 
						|
    OSK_EMPTY| KFLAG_HALF, 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L',
 | 
						|
    OSK_CHARSET1 | KFLAG_PLUS_HALF, 'Z', 'X', 'C', 'V', 'B', 'N', 'M', OSK_BACKSPACE | KFLAG_PLUS_HALF, OSK_EMPTY,
 | 
						|
    OSK_CHARSET3 | KS(2), ' ' | KS(5), '.', OSK_ENTER | KS(2),
 | 
						|
    0
 | 
						|
};
 | 
						|
 | 
						|
static const uint32_t normalKeycodeMapCharset3[] = {
 | 
						|
    '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
 | 
						|
    OSK_EMPTY | KFLAG_HALF, '@', '#', '$', '%', '&', '-', '+', '(', ')',
 | 
						|
    OSK_CHARSET4 | KFLAG_PLUS_HALF, '*', '"', '\'', ':', ';', '!', '?', OSK_BACKSPACE | KFLAG_PLUS_HALF, OSK_EMPTY,
 | 
						|
    OSK_CHARSET1 | KS(2), ',', '_', ' ' | KS(3), '/', OSK_ENTER | KS(2),
 | 
						|
    0
 | 
						|
};
 | 
						|
 | 
						|
static const uint32_t normalKeycodeMapCharset4[] = {
 | 
						|
    '~', '`', '|', '<', '>', '-', '+', '!', '?', ';',
 | 
						|
    OSK_EMPTY | KFLAG_HALF, '^', '\\', '$', '%', '&', '-', '+', '{', '}',
 | 
						|
    OSK_CHARSET3 | KFLAG_PLUS_HALF, '*', '"', '\'', ':', ';', '[', ']', OSK_BACKSPACE | KFLAG_PLUS_HALF, OSK_EMPTY,
 | 
						|
    OSK_CHARSET1 | KS(2), ',', ' ' | KS(4), '/', OSK_ENTER | KS(2),
 | 
						|
    0
 | 
						|
};
 | 
						|
 | 
						|
static const uint32_t *normalKeycodeMapCharsetMapping[] = {
 | 
						|
    normalKeycodeMapCharset4, // OSK_CHARSET4
 | 
						|
    normalKeycodeMapCharset3, // OSK_CHARSET3
 | 
						|
    normalKeycodeMapCharset2, // OSK_CHARSET2
 | 
						|
    normalKeycodeMapCharset1, // OSK_CHARSET1
 | 
						|
};
 | 
						|
 | 
						|
// rows, cols
 | 
						|
static const uint32_t normalKeycodeMapDimensions[] = { 4, 10 };
 | 
						|
 | 
						|
#define PADDING (8*DPI_MUL)
 | 
						|
 | 
						|
struct keyboard_btn_data {
 | 
						|
    struct keyboard *k;
 | 
						|
    int btn_idx;
 | 
						|
};
 | 
						|
 | 
						|
static int keyboard_init_map(struct keyboard *k, const uint32_t *map, const uint32_t *dimen);
 | 
						|
 | 
						|
 | 
						|
static int keyboard_charset_switch_worker(UNUSED uint32_t diff, void *data)
 | 
						|
{
 | 
						|
    void **keyboard_bnt_data_old = NULL;
 | 
						|
    struct keyboard_btn_data *d = data;
 | 
						|
    uint8_t keycode = (d->k->keycode_map[d->btn_idx] & 0xFF);
 | 
						|
 | 
						|
    fb_batch_start();
 | 
						|
    list_clear(&d->k->btns, &button_destroy);
 | 
						|
    list_swap(&d->k->keyboard_bnt_data, &keyboard_bnt_data_old);
 | 
						|
    keyboard_init_map(d->k, normalKeycodeMapCharsetMapping[keycode - OSK_CHARSET4], normalKeycodeMapDimensions);
 | 
						|
    fb_batch_end();
 | 
						|
    fb_request_draw();
 | 
						|
 | 
						|
    list_clear(&keyboard_bnt_data_old, free);
 | 
						|
    return 1;
 | 
						|
}
 | 
						|
 | 
						|
static void keyboard_btn_clicked(void *data)
 | 
						|
{
 | 
						|
    struct keyboard_btn_data *d = data;
 | 
						|
    uint8_t keycode = (d->k->keycode_map[d->btn_idx] & 0xFF);
 | 
						|
 | 
						|
    if(keycode >= OSK_CHARSET4 && keycode <= OSK_CHARSET1)
 | 
						|
        workers_add(keyboard_charset_switch_worker, data);
 | 
						|
    else if(d->k->key_pressed)
 | 
						|
        d->k->key_pressed(d->k->key_pressed_data, keycode);
 | 
						|
}
 | 
						|
 | 
						|
int keyboard_init_map(struct keyboard *k, const uint32_t *map, const uint32_t *dimen)
 | 
						|
{
 | 
						|
    button *btn;
 | 
						|
    int i, idx = 0;
 | 
						|
    uint32_t col = 0;
 | 
						|
    char buf[2] = { 0 };
 | 
						|
    uint8_t code;
 | 
						|
 | 
						|
    int x = k->x + PADDING;
 | 
						|
    int y = k->y + PADDING;
 | 
						|
    int w;
 | 
						|
    const int btn_w = (k->w - PADDING*(dimen[1]+1)) /dimen[1];
 | 
						|
    const int btn_h = (k->h - PADDING*(dimen[0]+1)) /dimen[0];
 | 
						|
 | 
						|
    for(i = 0; map[i]; ++i)
 | 
						|
    {
 | 
						|
        code = (map[i] & 0xFF);
 | 
						|
        w = (GET_KS(map[i])+1)*btn_w + PADDING*GET_KS(map[i]);
 | 
						|
 | 
						|
        if(map[i] & KFLAG_HALF)
 | 
						|
            w /= 2;
 | 
						|
        else if(map[i] & KFLAG_PLUS_HALF)
 | 
						|
            w = w*1.5 + PADDING*0.5;
 | 
						|
 | 
						|
        if(code != OSK_EMPTY)
 | 
						|
        {
 | 
						|
            btn = mzalloc(sizeof(button));
 | 
						|
            btn->x = x;
 | 
						|
            btn->y = y;
 | 
						|
            btn->w = w;
 | 
						|
            btn->h = btn_h;
 | 
						|
 | 
						|
            struct keyboard_btn_data *d = mzalloc(sizeof(struct keyboard_btn_data));
 | 
						|
            d->k = k;
 | 
						|
            d->btn_idx = i;
 | 
						|
            btn->clicked_data = d;
 | 
						|
            btn->clicked = keyboard_btn_clicked;
 | 
						|
 | 
						|
            buf[0] = (map[i] & 0xFF);
 | 
						|
            button_init_ui(btn, ((int8_t)buf[0]) >= 0 ? buf : specialKeys[0xFF - (map[i] & 0xFF)], SIZE_NORMAL);
 | 
						|
            list_add(&k->btns, btn);
 | 
						|
            list_add(&k->keyboard_bnt_data, d);
 | 
						|
        }
 | 
						|
 | 
						|
        col += GET_KS(map[i])+1;
 | 
						|
        if(col < dimen[1])
 | 
						|
            x += w + PADDING;
 | 
						|
        else
 | 
						|
        {
 | 
						|
            x = k->x + PADDING;
 | 
						|
            y += btn_h + PADDING;
 | 
						|
            col = 0;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    k->keycode_map = map;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
struct keyboard *keyboard_create(int type, int x, int y, int w, int h)
 | 
						|
{
 | 
						|
    struct keyboard *k = mzalloc(sizeof(struct keyboard));
 | 
						|
    k->x = x;
 | 
						|
    k->y = y;
 | 
						|
    k->w = w;
 | 
						|
    k->h = h;
 | 
						|
 | 
						|
    switch(type)
 | 
						|
    {
 | 
						|
        case KEYBOARD_PIN:
 | 
						|
            keyboard_init_map(k, pinKeycodeMap, pinKeycodeMapDimensions);
 | 
						|
            break;
 | 
						|
        case KEYBOARD_NORMAL:
 | 
						|
        default:
 | 
						|
            keyboard_init_map(k, normalKeycodeMapCharset1, normalKeycodeMapDimensions);
 | 
						|
            break;
 | 
						|
    }
 | 
						|
 | 
						|
    return k;
 | 
						|
}
 | 
						|
 | 
						|
void keyboard_destroy(struct keyboard *k)
 | 
						|
{
 | 
						|
    list_clear(&k->btns, &button_destroy);
 | 
						|
    list_clear(&k->keyboard_bnt_data, free);
 | 
						|
    free(k);
 | 
						|
}
 | 
						|
 | 
						|
void keyboard_set_callback(struct keyboard *k, keyboard_on_pressed_callback callback, void *data)
 | 
						|
{
 | 
						|
    k->key_pressed = callback;
 | 
						|
    k->key_pressed_data = data;
 | 
						|
}
 |