Hello, this patch includes – framebuffer pages for the kernel console. – a german keyboard layout
Greetings Sebastian Köln
# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: [email protected]\ # xb0q6vcatglacxwn # target_branch: file:///home/sebk/src/HelenOS_amd64/ # testament_sha1: e7442271c9bcea188d9cfcb401f8a6e238efbdd1 # timestamp: 2014-03-15 16:51:12 +0100 # source_branch: bzr://bzr.helenos.org/mainline # base_revision_id: [email protected]\ # knzz139kseh0g2zl # # Begin patch === modified file 'kernel/genarch/src/fb/fb.c' --- kernel/genarch/src/fb/fb.c 2013-04-09 17:42:52 +0000 +++ kernel/genarch/src/fb/fb.c 2014-03-15 15:48:26 +0000 @@ -54,6 +54,7 @@ #define BG_COLOR 0x001620 #define FG_COLOR 0xf3cf65 #define INV_COLOR 0xaaaaaa +#define FB_PAGES 10 /* how many pages the pager contains */ #define RED(x, bits) (((x) >> (8 + 8 + 8 - (bits))) & ((1 << (bits)) - 1)) #define GREEN(x, bits) (((x) >> (8 + 8 - (bits))) & ((1 << (bits)) - 1)) @@ -69,7 +70,7 @@ ((y) * (instance)->scanline + (x) * (instance)->pixelbytes) #define BB_POS(instance, col, row) \ - ((row) * (instance)->cols + (col)) + ((((instance)->first_row + (row)) % (instance)->rows) * (instance)->cols + (col)) #define GLYPH_POS(instance, glyph, y) \ ((glyph) * (instance)->glyphbytes + (y) * (instance)->glyphscanline) @@ -91,7 +92,7 @@ unsigned int xres; unsigned int yres; - unsigned int rowtrim; + unsigned int rowtrim; /** number of rows that fit on the screen */ unsigned int scanline; unsigned int glyphscanline; @@ -101,9 +102,14 @@ unsigned int bgscanbytes; unsigned int cols; - unsigned int rows; - - unsigned int position; + unsigned int rows; /** Number of rows in the backbuffer */ + unsigned int first_row; /** First row of backbuffer that is visible on the screen */ + + unsigned int position; /** Position relative to first_row */ + + /** Visible offset in rows between active write and view row. + * Valid range: [ 0, rows - rowtrim ) */ + unsigned int page_row_offset; } fb_instance_t; static void fb_putchar(outdev_t *dev, wchar_t ch); @@ -239,7 +245,7 @@ if ((!instance->parea.mapped) || (console_override)) { unsigned int row; - for (row = 0; row < instance->rows; row++) { + for (row = 0; row < instance->rowtrim; row++) { unsigned int y = ROW2Y(row); unsigned int yd; @@ -251,7 +257,7 @@ col++, x += FONT_WIDTH) { uint16_t glyph; - if (row < instance->rows - 1) { + if (row < instance->rowtrim - 1) { if (instance->backbuf[BB_POS(instance, col, row)] == instance->backbuf[BB_POS(instance, col, row + 1)]) continue; @@ -268,9 +274,11 @@ } } - memmove(instance->backbuf, &instance->backbuf[BB_POS(instance, 0, 1)], - instance->cols * (instance->rows - 1) * sizeof(uint16_t)); - memsetw(&instance->backbuf[BB_POS(instance, 0, instance->rows - 1)], + instance->first_row++; + if( instance->first_row >= 2 * instance->rows ) + instance->first_row -= instance->rows; + + memsetw(&instance->backbuf[BB_POS(instance, 0, instance->rowtrim - 1)], instance->cols, 0); } @@ -343,44 +351,92 @@ fb_instance_t *instance = (fb_instance_t *) dev->data; spinlock_lock(&instance->lock); - switch (ch) { - case '\n': - cursor_remove(instance); - instance->position += instance->cols; - instance->position -= instance->position % instance->cols; - break; - case '\r': - cursor_remove(instance); - instance->position -= instance->position % instance->cols; - break; - case '\b': - cursor_remove(instance); - if (instance->position % instance->cols) - instance->position--; - break; - case '\t': - cursor_remove(instance); - do { - glyph_draw(instance, fb_font_glyph(' '), - instance->position % instance->cols, - instance->position / instance->cols, false); - instance->position++; - } while (((instance->position % instance->cols) % 8 != 0) && - (instance->position < instance->cols * instance->rows)); - break; - default: - glyph_draw(instance, fb_font_glyph(ch), - instance->position % instance->cols, - instance->position / instance->cols, false); - instance->position++; - } - - if (instance->position >= instance->cols * instance->rows) { - instance->position -= instance->cols; - screen_scroll(instance); - } - - cursor_put(instance); + if (ch == U_PAGE_UP) { + unsigned int move_rows = instance->rowtrim / 2; + + /* are we still in the valid range? */ + if (move_rows + instance->page_row_offset >= instance->rows - instance->rowtrim) { + /* out of range. scroll to the maximum possible offset */ + move_rows = instance->rows - instance->rowtrim - 1 - instance->page_row_offset; + } else if (move_rows > instance->first_row) { + /* avoid moving into empty areas */ + move_rows = instance->first_row; + } + + if (move_rows) { + instance->first_row -= move_rows; + instance->page_row_offset += move_rows; + + fb_redraw_internal(instance); + } + } else if (ch == U_PAGE_DOWN) { + unsigned int move_rows = instance->rowtrim / 2; + + /* are we still in the valid range? */ + if (move_rows > instance->page_row_offset) { + /* out of range. scroll to the maximum possible offset */ + move_rows = instance->page_row_offset; + } + + if (move_rows) { + instance->first_row += move_rows; + instance->page_row_offset -= move_rows; + + fb_redraw_internal(instance); + + /* if we reached the active screen, restore the cursor */ + if (instance->page_row_offset == 0) + cursor_put(instance); + } + } else { + /* ensure we display the last part of the buffer */ + if( instance->page_row_offset ) { + /* correct offset into backbuffer */ + instance->first_row += instance->page_row_offset; + instance->page_row_offset = 0; + + fb_redraw_internal(instance); + } + + switch (ch) { + case '\n': + cursor_remove(instance); + instance->position += instance->cols; + instance->position -= instance->position % instance->cols; + break; + case '\r': + cursor_remove(instance); + instance->position -= instance->position % instance->cols; + break; + case '\b': + cursor_remove(instance); + if (instance->position % instance->cols) + instance->position--; + break; + case '\t': + cursor_remove(instance); + do { + glyph_draw(instance, fb_font_glyph(' '), + instance->position % instance->cols, + instance->position / instance->cols, false); + instance->position++; + } while (((instance->position % instance->cols) % 8 != 0) && + (instance->position < instance->cols * instance->rowtrim)); + break; + default: + glyph_draw(instance, fb_font_glyph(ch), + instance->position % instance->cols, + instance->position / instance->cols, false); + instance->position++; + } + + if (instance->position >= instance->cols * instance->rowtrim) { + instance->position -= instance->cols; + screen_scroll(instance); + } + + cursor_put(instance); + } spinlock_unlock(&instance->lock); } @@ -522,12 +578,14 @@ instance->xres = props->x; instance->yres = props->y; instance->scanline = props->scan; + instance->first_row = 0; + instance->page_row_offset = 0; instance->position = 0; instance->cols = X2COL(instance->xres); - instance->rows = Y2ROW(instance->yres); + instance->rowtrim = Y2ROW(instance->yres); - instance->rowtrim = instance->rows; + instance->rows = FB_PAGES * instance->rowtrim; instance->glyphscanline = FONT_WIDTH * instance->pixelbytes; instance->glyphbytes = ROW2Y(instance->glyphscanline); === modified file 'uspace/drv/bus/usb/usbhid/kbd/conv.c' --- uspace/drv/bus/usb/usbhid/kbd/conv.c 2012-04-02 15:52:07 +0000 +++ uspace/drv/bus/usb/usbhid/kbd/conv.c 2014-03-15 15:50:37 +0000 @@ -136,7 +136,7 @@ [0x51] = KC_DOWN, [0x52] = KC_UP, - //[0x64] = // some funny key + [0x64] = KC_BAR, // only some non-US keyboards [0xe0] = KC_LCTRL, [0xe1] = KC_LSHIFT, === modified file 'uspace/drv/char/xtkbd/xtkbd.c' --- uspace/drv/char/xtkbd/xtkbd.c 2012-08-17 11:37:03 +0000 +++ uspace/drv/char/xtkbd/xtkbd.c 2014-03-15 15:50:37 +0000 @@ -95,6 +95,7 @@ [0x2b] = KC_BACKSLASH, [0x2a] = KC_LSHIFT, + [0x56] = KC_BAR, [0x2c] = KC_Z, [0x2d] = KC_X, @@ -281,7 +282,7 @@ const kbd_event_type_t type = (code & 0x80) ? KEY_RELEASE : KEY_PRESS; code &= ~0x80; - + const unsigned key = (code < map_size) ? map[code] : 0; if (key != 0) { async_exch_t *exch = === modified file 'uspace/lib/c/include/io/keycode.h' --- uspace/lib/c/include/io/keycode.h 2012-04-02 15:52:07 +0000 +++ uspace/lib/c/include/io/keycode.h 2014-03-15 15:50:37 +0000 @@ -112,6 +112,8 @@ /* Main block row 4 */ KC_LSHIFT, + + KC_BAR, /* present on some non-US keyboards: mostly with labels '<' and '>' */ KC_Z, KC_X, === modified file 'uspace/srv/hid/compositor/compositor.c' --- uspace/srv/hid/compositor/compositor.c 2014-03-01 23:05:38 +0000 +++ uspace/srv/hid/compositor/compositor.c 2014-03-15 15:50:37 +0000 @@ -81,6 +81,7 @@ #ifndef ANIMATE_WINDOW_TRANSFORMS #define ANIMATE_WINDOW_TRANSFORMS 0 #endif +#define HID_COMPOSITOR_MOD_KEY KM_LALT static char *server_name; static sysarg_t coord_origin; @@ -1799,20 +1800,20 @@ static int comp_key_press(input_t *input, kbd_event_type_t type, keycode_t key, keymod_t mods, wchar_t c) { - bool win_transform = (mods & KM_ALT) && ( + bool win_transform = (mods & HID_COMPOSITOR_MOD_KEY) && ( key == KC_W || key == KC_S || key == KC_A || key == KC_D || key == KC_Q || key == KC_E || key == KC_R || key == KC_F); - bool win_resize = (mods & KM_ALT) && ( + bool win_resize = (mods & HID_COMPOSITOR_MOD_KEY) && ( key == KC_T || key == KC_G || key == KC_B || key == KC_N); - bool win_opacity = (mods & KM_ALT) && ( + bool win_opacity = (mods & HID_COMPOSITOR_MOD_KEY) && ( key == KC_C || key == KC_V); - bool win_close = (mods & KM_ALT) && (key == KC_X); - bool win_switch = (mods & KM_ALT) && (key == KC_TAB); - bool viewport_move = (mods & KM_ALT) && ( + bool win_close = (mods & HID_COMPOSITOR_MOD_KEY) && (key == KC_X); + bool win_switch = (mods & HID_COMPOSITOR_MOD_KEY) && (key == KC_TAB); + bool viewport_move = (mods & HID_COMPOSITOR_MOD_KEY) && ( key == KC_I || key == KC_K || key == KC_J || key == KC_L); - bool viewport_change = (mods & KM_ALT) && ( + bool viewport_change = (mods & HID_COMPOSITOR_MOD_KEY) && ( key == KC_O || key == KC_P); - bool kconsole_switch = (mods & KM_ALT) && (key == KC_M); + bool kconsole_switch = (mods & HID_COMPOSITOR_MOD_KEY) && (key == KC_M); bool filter = (type == KEY_RELEASE) && (win_transform || win_resize || win_opacity || win_close || win_switch || viewport_move || === modified file 'uspace/srv/hid/input/Makefile' --- uspace/srv/hid/input/Makefile 2013-03-12 21:07:15 +0000 +++ uspace/srv/hid/input/Makefile 2014-03-15 15:50:37 +0000 @@ -35,6 +35,7 @@ layout/us_qwerty.c \ layout/us_dvorak.c \ layout/ar.c \ + layout/de.c \ port/adb.c \ port/adb_mouse.c \ port/chardev.c \ === modified file 'uspace/srv/hid/input/ctl/pc.c' --- uspace/srv/hid/input/ctl/pc.c 2012-08-16 19:14:03 +0000 +++ uspace/srv/hid/input/ctl/pc.c 2014-03-15 15:50:37 +0000 @@ -127,6 +127,7 @@ [0x2b] = KC_BACKSLASH, [0x2a] = KC_LSHIFT, + [0x56] = KC_BAR, // only some non-US keyboards [0x2c] = KC_Z, [0x2d] = KC_X, === modified file 'uspace/srv/hid/input/input.c' --- uspace/srv/hid/input/input.c 2013-09-10 16:32:35 +0000 +++ uspace/srv/hid/input/input.c 2014-03-15 15:50:37 +0000 @@ -61,13 +61,14 @@ #include "mouse_proto.h" #include "input.h" -#define NUM_LAYOUTS 4 +#define NUM_LAYOUTS 5 static layout_ops_t *layout[NUM_LAYOUTS] = { &us_qwerty_ops, &us_dvorak_ops, &cz_ops, - &ar_ops + &ar_ops, + &de_ops, }; static void kbd_devs_yield(void); @@ -170,6 +171,13 @@ return; } + if (type == KEY_PRESS && (kdev->mods & KM_LCTRL) && + key == KC_F5) { + layout_destroy(kdev->active_layout); + kdev->active_layout = layout_create(layout[4]); + return; + } + ev.type = type; ev.key = key; ev.mods = kdev->mods; === modified file 'uspace/srv/hid/input/layout.h' --- uspace/srv/hid/input/layout.h 2012-12-17 21:36:02 +0000 +++ uspace/srv/hid/input/layout.h 2014-03-15 15:50:37 +0000 @@ -60,6 +60,7 @@ extern layout_ops_t us_dvorak_ops; extern layout_ops_t cz_ops; extern layout_ops_t ar_ops; +extern layout_ops_t de_ops; extern layout_t *layout_create(layout_ops_t *); extern void layout_destroy(layout_t *); === added file 'uspace/srv/hid/input/layout/de.c' --- uspace/srv/hid/input/layout/de.c 1970-01-01 00:00:00 +0000 +++ uspace/srv/hid/input/layout/de.c 2014-03-15 15:50:37 +0000 @@ -0,0 +1,689 @@ +/* + * Copyright (c) 2014 Sebastian Köln + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @addtogroup input + * @brief German QWERTZ layout. + * @{ + */ + +#include <errno.h> +#include <io/console.h> +#include <io/keycode.h> +#include <stdbool.h> +#include <stdlib.h> +#include <io/log.h> +#include "../input.h" +#include "../layout.h" + +static int de_create(layout_t*); +static void de_destroy(layout_t*); +static wchar_t de_parse_ev(layout_t*, kbd_event_t* ev); + +enum m_state +{ + ms_normal, + ms_acute, + ms_grave, + ms_circumflex +}; + +typedef struct +{ + enum m_state mstate; +} layout_de_t; + +layout_ops_t de_ops = +{ + .create = de_create, + .destroy = de_destroy, + .parse_ev = de_parse_ev +}; + +/** Keys affected by either SHIFT or CAPS-LOCK (lowercase variant) */ +static wchar_t map_lcase[] = +{ + [KC_Q] = 'q', + [KC_W] = 'w', + [KC_E] = 'e', + [KC_R] = 'r', + [KC_T] = 't', + [KC_Y] = 'z', + [KC_U] = 'u', + [KC_I] = 'i', + [KC_O] = 'o', + [KC_P] = 'p', + + [KC_LBRACKET] = L'ü', + + [KC_A] = 'a', + [KC_S] = 's', + [KC_D] = 'd', + [KC_F] = 'f', + [KC_G] = 'g', + [KC_H] = 'h', + [KC_J] = 'j', + [KC_K] = 'k', + [KC_L] = 'l', + + [KC_SEMICOLON] = L'ö', + [KC_QUOTE] = L'ä', + + [KC_Z] = 'y', + [KC_X] = 'x', + [KC_C] = 'c', + [KC_V] = 'v', + [KC_B] = 'b', + [KC_N] = 'n', + [KC_M] = 'm', +}; + +/** Keys affected by either SHIFT or CAPS-LOCK (uppercase variant) */ +static wchar_t map_ucase[] = +{ + [KC_Q] = 'Q', + [KC_W] = 'W', + [KC_E] = 'E', + [KC_R] = 'R', + [KC_T] = 'T', + [KC_Y] = 'Z', + [KC_U] = 'U', + [KC_I] = 'I', + [KC_O] = 'O', + [KC_P] = 'P', + + [KC_LBRACKET] = L'Ü', + + [KC_A] = 'A', + [KC_S] = 'S', + [KC_D] = 'D', + [KC_F] = 'F', + [KC_G] = 'G', + [KC_H] = 'H', + [KC_J] = 'J', + [KC_K] = 'K', + [KC_L] = 'L', + + [KC_SEMICOLON] = L'Ö', + [KC_QUOTE] = L'Ä', + + [KC_Z] = 'Y', + [KC_X] = 'X', + [KC_C] = 'C', + [KC_V] = 'V', + [KC_B] = 'B', + [KC_N] = 'N', + [KC_M] = 'M', +}; + +/** Keys that only depend on the SHIFT-state (inactive) */ +static wchar_t map_not_shifted[] = +{ + [KC_BACKTICK] = '^', + [KC_1] = '1', + [KC_2] = '2', + [KC_3] = '3', + [KC_4] = '4', + [KC_5] = '5', + [KC_6] = '6', + [KC_7] = '7', + [KC_8] = '8', + [KC_9] = '9', + [KC_0] = '0', + + [KC_MINUS] = L'ß', + [KC_EQUALS] = L'´', + + [KC_RBRACKET] = '+', + + [KC_BACKSLASH] = '#', + + [KC_BAR] = '<', + [KC_COMMA] = ',', + [KC_PERIOD] = '.', + [KC_SLASH] = '-', +}; + +/** Keys that only depend on the SHIFT-state (active) */ +static wchar_t map_shifted[] = +{ + [KC_BACKTICK] = L'°', + + [KC_1] = '!', + [KC_2] = '"', + [KC_3] = L'§', + [KC_4] = '$', + [KC_5] = '%', + [KC_6] = '&', + [KC_7] = '/', + [KC_8] = '(', + [KC_9] = ')', + [KC_0] = '=', + + [KC_MINUS] = '?', + [KC_EQUALS] = L'`', + + [KC_RBRACKET] = '*', + + [KC_BACKSLASH] = '\'', + + [KC_BAR] = '>', + [KC_COMMA] = ';', + [KC_PERIOD] = ':', + [KC_SLASH] = '_', +}; + +/** Keys affected by disabled CAPS-LOCK during inactive SHIFT state */ +static wchar_t map_ns_nocaps[] = +{ + [KC_EQUALS] = L'ß' +}; + +/** Keys affected by enabled CAPS-LOCK during inactive SHIFT state */ +static wchar_t map_ns_caps[] = +{ + [KC_EQUALS] = L'ẞ' +}; + +/** Keys affected by ALT-GR without SHIFT */ +static wchar_t map_altgr_not_shifted[] = +{ + [KC_1] = L'¹', + [KC_2] = L'²', + [KC_3] = L'³', + [KC_4] = L'¼', + [KC_5] = L'½', + [KC_6] = L'¬', + [KC_7] = '{', + [KC_8] = '[', + [KC_9] = ']', + [KC_0] = '}', + + [KC_MINUS] = '\\', + + [KC_Q] = '@', + [KC_W] = L'ł', + [KC_E] = L'€', + [KC_R] = L'¶', + [KC_T] = L'ŧ', + [KC_Y] = L'←', + [KC_U] = L'↓', + [KC_I] = L'→', + [KC_O] = L'ø', + [KC_P] = L'þ', + + [KC_RBRACKET] = '~', + + [KC_A] = L'æ', + [KC_S] = L'ſ', + [KC_D] = L'ð', + [KC_F] = L'đ', + [KC_G] = L'ŋ', + [KC_H] = L'ħ', + [KC_K] = L'ĸ', + + [KC_BACKSLASH] = L'’', + + [KC_BAR] = L'|', + [KC_Z] = L'»', + [KC_X] = L'«', + [KC_C] = L'¢', + [KC_V] = L'„', + [KC_B] = L'“', + [KC_N] = L'”', + [KC_M] = L'µ', + + [KC_COMMA] = L'·', + [KC_PERIOD] = L'…', + [KC_SLASH] = L'–', +}; + +/** Keys affected by ALT-GR with SHIFT */ +static wchar_t map_altgr_shifted[] = +{ + [KC_1] = L'¡', + [KC_2] = L'⅛', + [KC_3] = L'£', + [KC_4] = L'¤', + [KC_5] = L'⅜', + [KC_6] = L'⅝', + [KC_7] = L'⅞', + [KC_8] = L'™', + [KC_9] = L'±', + [KC_MINUS] = L'¿', + + [KC_Q] = L'Ω', + [KC_W] = L'Ł', + [KC_E] = L'€', + [KC_R] = L'®', + [KC_T] = L'Ŧ', + [KC_Y] = L'¥', + [KC_U] = L'↑', + [KC_I] = L'ı', + [KC_O] = L'Ø', + [KC_P] = L'Þ', + + [KC_RBRACKET] = '~', + + [KC_A] = L'Æ', + [KC_D] = L'Ð', + [KC_F] = L'ª', + [KC_G] = L'Ŋ', + [KC_H] = L'Ħ', + [KC_L] = L'Ł', + + [KC_BAR] = L'¦', + [KC_Z] = L'›', + [KC_X] = L'‹', + [KC_C] = L'©', + [KC_V] = L'‚', + [KC_B] = L'‘', + [KC_N] = L'’', + [KC_M] = L'º', + + [KC_COMMA] = L'×', + [KC_PERIOD] = L'÷', + [KC_SLASH] = L'—', +}; + +/** keys affected by acute modifier (lower case variant) */ +static wchar_t map_acute_lcase[] = +{ + [KC_EQUALS] = L'´', + + [KC_W] = L'ẃ', + [KC_E] = L'é', + [KC_R] = L'ŕ', + [KC_Y] = L'ź', + [KC_U] = L'ú', + [KC_I] = L'í', + [KC_O] = L'ó', + [KC_P] = L'ṕ', + + [KC_A] = L'á', + [KC_S] = L'ś', + [KC_G] = L'ǵ', + + [KC_Z] = L'ý', + [KC_C] = L'ć', + [KC_V] = L'ǘ', + [KC_N] = L'ń', + [KC_M] = L'ḿ', + + [KC_SPACE] = '\'', +}; + +/** keys affected by acute modifier (upper case variant) */ +static wchar_t map_acute_ucase[] = +{ + [KC_W] = L'Ẃ', + [KC_E] = L'É', + [KC_R] = L'Ŕ', + [KC_Y] = L'Ź', + [KC_U] = L'Ú', + [KC_I] = L'Í', + [KC_O] = L'Ó', + [KC_P] = L'Ṕ', + + [KC_A] = L'Á', + [KC_S] = L'Ś', + [KC_G] = L'Ǵ', + + [KC_Z] = L'Ý', + [KC_C] = L'Ć', + [KC_V] = L'Ǘ', + [KC_N] = L'Ń', + [KC_M] = L'Ḿ', + + [KC_SPACE] = '\'', +}; + +/** keys affected by grave modifier (lower case variant) */ +static wchar_t map_grave_lcase[] = +{ + [KC_W] = L'ẁ', + [KC_E] = L'è', + [KC_U] = L'ù', + [KC_I] = L'ì', + [KC_O] = L'ò', + + [KC_A] = L'à', + + [KC_Z] = L'ỳ', + [KC_V] = L'ǜ', + [KC_N] = L'ǹ', + + [KC_SPACE] = '`', +}; + +/** keys affected by grave modifier (upper case variant) */ +static wchar_t map_grave_ucase[] = +{ + [KC_EQUALS] = L'`', + + [KC_W] = L'Ẁ', + [KC_E] = L'È', + [KC_U] = L'Ù', + [KC_I] = L'Ì', + [KC_O] = L'Ò', + + [KC_A] = L'À', + + [KC_Z] = L'Ỳ', + [KC_V] = L'Ǜ', + [KC_N] = L'Ǹ', + + [KC_SPACE] = '`', +}; + + +/** keys affected by circumvlex modifier (lower case variant) */ +static wchar_t map_circumflex_lcase[] = +{ + [KC_BACKTICK] = '^', + + [KC_1] = L'¹', + [KC_2] = L'²', + [KC_3] = L'³', + [KC_4] = L'⁴', + [KC_5] = L'⁵', + [KC_6] = L'⁶', + [KC_7] = L'⁷', + [KC_8] = L'⁸', + [KC_9] = L'⁹', + [KC_0] = L'⁰', + + [KC_W] = L'ŵ', + [KC_E] = L'ê', + [KC_Y] = L'ẑ', + [KC_U] = L'û', + [KC_I] = L'î', + [KC_O] = L'ô', + + [KC_A] = L'â', + [KC_S] = L'ŝ', + [KC_G] = L'ĝ', + [KC_H] = L'ĥ', + [KC_J] = L'ĵ', + + [KC_Z] = L'ŷ', + [KC_C] = L'ĉ', + + [KC_SPACE] = '^', +}; + +/** keys affected by circumvlex modifier (upper case variant) */ +static wchar_t map_circumflex_ucase[] = +{ + [KC_W] = L'Ŵ', + [KC_E] = L'Ê', + [KC_Y] = L'Ẑ', + [KC_U] = L'Û', + [KC_I] = L'Î', + [KC_O] = L'Ô', + + [KC_A] = L'Â', + [KC_S] = L'Ŝ', + [KC_G] = L'Ĝ', + [KC_H] = L'Ĥ', + [KC_J] = L'Ĵ', + + [KC_Z] = L'Ŷ', + [KC_C] = L'Ĉ', + + [KC_SPACE] = '^', +}; + +/** keys that are independend of SHIFT-state. */ +static wchar_t map_neutral[] = +{ + [KC_BACKSPACE] = '\b', + [KC_TAB] = '\t', + [KC_ENTER] = '\n', + [KC_SPACE] = ' ', + + [KC_NSLASH] = '/', + [KC_NTIMES] = '*', + [KC_NMINUS] = '-', + [KC_NPLUS] = '+', + [KC_NENTER] = '\n' +}; + +static wchar_t map_numeric[] = +{ + [KC_N7] = '7', + [KC_N8] = '8', + [KC_N9] = '9', + [KC_N4] = '4', + [KC_N5] = '5', + [KC_N6] = '6', + [KC_N1] = '1', + [KC_N2] = '2', + [KC_N3] = '3', + + [KC_N0] = '0', + [KC_NPERIOD] = '.' +}; + +static wchar_t translate(unsigned int key, wchar_t* map, size_t map_length) +{ + if (key >= map_length) + return 0; + + return map[key]; +} + +/** @brief: handle key sequences of modifier key and an additional key */ +static wchar_t parse_ms_modifier(layout_de_t* de_state, kbd_event_t* ev) +{ + wchar_t* map_table = NULL; + size_t map_size = 0; + + if (((ev->mods & KM_SHIFT) != 0) ^ ((ev->mods & KM_CAPS_LOCK) != 0)) + { + switch (de_state->mstate) + { + case ms_acute: + map_table = map_acute_ucase; + map_size = sizeof(map_acute_ucase) / sizeof(wchar_t); + break; + + case ms_grave: + map_table = map_grave_ucase; + map_size = sizeof(map_grave_ucase) / sizeof(wchar_t); + break; + + case ms_circumflex: + map_table = map_circumflex_ucase; + map_size = sizeof(map_circumflex_ucase) / sizeof(wchar_t); + break; + + default: + break; + } + } + else + { + switch (de_state->mstate) + { + case ms_acute: + map_table = map_acute_lcase; + map_size = sizeof(map_acute_lcase) / sizeof(wchar_t); + break; + + case ms_grave: + map_table = map_grave_lcase; + map_size = sizeof(map_grave_lcase) / sizeof(wchar_t); + break; + + case ms_circumflex: + map_table = map_circumflex_lcase; + map_size = sizeof(map_circumflex_lcase) / sizeof(wchar_t); + break; + + default: + break; + } + } + + if (map_table) + return translate(ev->key, map_table, map_size); + else + return 0; +} + +static wchar_t parse_ms_normal(layout_de_t* de_state, kbd_event_t* ev) +{ + wchar_t c; + + /* AltGr combinations */ + if ((ev->mods & KM_RALT) != 0) + { + if ((ev->mods & KM_SHIFT) != 0) + c = translate(ev->key, map_altgr_shifted, sizeof(map_altgr_shifted) / sizeof(wchar_t)); + else + c = translate(ev->key, map_altgr_not_shifted, sizeof(map_altgr_not_shifted) / sizeof(wchar_t)); + + return c; + } + + c = translate(ev->key, map_neutral, sizeof(map_neutral) / sizeof(wchar_t)); + + if (c != 0) + return c; + + /* Caps-Lock effects */ + if ((ev->mods & KM_SHIFT) == 0) + { + if ((ev->mods & KM_CAPS_LOCK) != 0) + c = translate(ev->key, map_ns_caps, sizeof(map_ns_caps) / sizeof(wchar_t)); + else + c = translate(ev->key, map_ns_nocaps, sizeof(map_ns_nocaps) / sizeof(wchar_t)); + + if (c != 0) + return c; + } + + if (((ev->mods & KM_SHIFT) != 0) ^ ((ev->mods & KM_CAPS_LOCK) != 0)) + c = translate(ev->key, map_ucase, sizeof(map_ucase) / sizeof(wchar_t)); + else + c = translate(ev->key, map_lcase, sizeof(map_lcase) / sizeof(wchar_t)); + + if (c != 0) + return c; + + if ((ev->mods & KM_SHIFT) != 0) + c = translate(ev->key, map_shifted, sizeof(map_shifted) / sizeof(wchar_t)); + else + c = translate(ev->key, map_not_shifted, sizeof(map_not_shifted) / sizeof(wchar_t)); + + if (c != 0) + return c; + + if ((ev->mods & KM_NUM_LOCK) != 0) + c = translate(ev->key, map_numeric, sizeof(map_numeric) / sizeof(wchar_t)); + else + c = 0; + + return c; +} + +static bool key_is_mod(unsigned key) +{ + switch (key) + { + case KC_LSHIFT: + case KC_RSHIFT: + case KC_LALT: + case KC_RALT: + case KC_LCTRL: + case KC_RCTRL: + return true; + + default: + return false; + } +} + +static int de_create(layout_t* state) +{ + layout_de_t* de_state; + + de_state = malloc(sizeof(layout_de_t)); + + if (de_state == NULL) + { + printf("%s: Out of memory.\n", NAME); + return ENOMEM; + } + + de_state->mstate = ms_normal; + state->layout_priv = (void*) de_state; + return EOK; +} + +static void de_destroy(layout_t* state) +{ + free(state->layout_priv); +} + +static wchar_t de_parse_ev(layout_t* state, kbd_event_t* ev) +{ + layout_de_t* de_state = (layout_de_t*) state->layout_priv; + int c = 0; + + if (ev->type != KEY_PRESS) + return 0; + + if (key_is_mod(ev->key)) + return 0; + + /* Produce no characters when Ctrl or Alt is pressed. */ + if ((ev->mods & (KM_CTRL | KM_LALT)) != 0) + return 0; + + if (de_state->mstate == ms_normal ) { + /* handle mode changes by '^', '´' and '`' keys */ + if ((ev->key == KC_BACKTICK) && ((ev->mods & KM_SHIFT) == 0)) + de_state->mstate = ms_circumflex; + else if ((ev->key == KC_EQUALS) && ((ev->mods & KM_SHIFT) == 0)) + de_state->mstate = ms_acute; + else if ((ev->key == KC_EQUALS) && ((ev->mods & KM_SHIFT) != 0)) + de_state->mstate = ms_grave; + else + c = parse_ms_normal(de_state, ev); + } else { + c = parse_ms_modifier(de_state, ev); + de_state->mstate = ms_normal; + } + + return c; +} + +/** + * @} + */ # Begin bundle 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
smime.p7s
Description: S/MIME cryptographic signature
_______________________________________________ HelenOS-devel mailing list [email protected] http://lists.modry.cz/listinfo/helenos-devel
