Logo Search packages:      
Sourcecode: fbterm version File versions  Download package

keycode.c

/*
 *   Copyright  2008 dragchan <zgchan317@gmail.com>
 *   This file is part of FbTerm.
 *
 *   This program 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 2
 *   of the License, or (at your option) any later version.
 *
 *   This program 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 this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/kd.h>
#include <linux/keyboard.h>
#include <linux/input.h>

static char key_down[NR_KEYS];
static unsigned char shift_down[NR_SHIFT];
static short shift_state;
static char lock_state;
static char cr_with_lf, applic_keypad, cursor_esco;
static int npadch;

void init_keycode_state()
{
      npadch = -1;
      shift_state = 0;
      bzero(key_down, sizeof(char) * NR_KEYS);
      bzero(shift_down, sizeof(char) * NR_SHIFT);
      ioctl(STDIN_FILENO, KDGKBLED, &lock_state);
}

void update_term_mode(char crlf, char appkey, char curo)
{
    cr_with_lf = crlf;
    applic_keypad = appkey;
    cursor_esco = curo;
}

unsigned short keycode_to_keysym(unsigned short keycode, char down)
{
      if (keycode >= NR_KEYS) return K_HOLE;

      char rep = (down && key_down[keycode]);
      key_down[keycode] = down;

      struct kbentry ke;
      ke.kb_table = shift_state;
      ke.kb_index = keycode;

      if (ioctl(STDIN_FILENO, KDGKBENT, &ke) == -1) return K_HOLE;

      if (KTYP(ke.kb_value) == KT_LETTER && (lock_state & K_CAPSLOCK)) {
            ke.kb_table = shift_state ^ (1 << KG_SHIFT);
            if (ioctl(STDIN_FILENO, KDGKBENT, &ke) == -1) return K_HOLE;
      }

      if (ke.kb_value == K_HOLE || ke.kb_value == K_NOSUCHMAP) return K_HOLE;

      unsigned value = KVAL(ke.kb_value);

      switch (KTYP(ke.kb_value)) {
      case KT_LETTER:
            ke.kb_value = K(KT_LATIN, value);
            break;

      case KT_SPEC:
            switch (ke.kb_value) {
            case K_NUM:
                  if (applic_keypad) break;
            case K_BARENUMLOCK:
            case K_CAPS:
            case K_CAPSON:
                  if (down && !rep) {
                        if (value == KVAL(K_NUM) || value == KVAL(K_BARENUMLOCK)) lock_state ^= K_NUMLOCK;
                        else if (value == KVAL(K_CAPS)) lock_state ^= K_CAPSLOCK;
                        else if (value == KVAL(K_CAPSON)) lock_state |= K_CAPSLOCK;

                        ioctl(STDIN_FILENO, KDSKBLED, lock_state);
                  }
                  break;

            default:
                  break;
            }
            break;

      case KT_SHIFT:
            if (value >= NR_SHIFT || rep) break;

            if (value == KVAL(K_CAPSSHIFT)) {
                  value = KVAL(K_SHIFT);

                  if (down && (lock_state & K_CAPSLOCK)) {
                        lock_state &= ~K_CAPSLOCK;
                        ioctl(STDIN_FILENO, KDSKBLED, lock_state);
                  }
            }
            
            if (down) shift_down[value]++;
            else if (shift_down[value]) shift_down[value]--;

            if (shift_down[value]) shift_state |= (1 << value);
            else shift_state &= ~(1 << value);

            break;

      case KT_DEAD:
      case KT_LOCK:
      case KT_SLOCK:
      case KT_BRL:
            printf("not support!\n");
            break;

      default:
            break;
      }

      return ke.kb_value;
}

unsigned short keypad_keysym_redirect(unsigned keysym)
{
      if (applic_keypad || KTYP(keysym) != KT_PAD || KVAL(keysym) >= NR_PAD) return keysym;
      
      #define KL(val) K(KT_LATIN, val)
      static const unsigned short num_map[] = {
            KL('0'), KL('1'), KL('2'), KL('3'), KL('4'),
            KL('5'), KL('6'), KL('7'), KL('8'), KL('9'),
            KL('+'), KL('-'), KL('*'), KL('/'), K_ENTER,
            KL(','), KL('.'), KL('?'), KL('('), KL(')'),
            KL('#')
      };

      static const unsigned short fn_map[] = {
            K_INSERT, K_SELECT, K_DOWN, K_PGDN, K_LEFT,
            K_P5, K_RIGHT, K_FIND, K_UP, K_PGUP,
            KL('+'), KL('-'), KL('*'), KL('/'), K_ENTER,
            K_REMOVE, K_REMOVE, KL('?'), KL('('), KL(')'),
            KL('#')
      };
      
      if (lock_state & K_NUMLOCK) return num_map[keysym - K_P0];
      return fn_map[keysym - K_P0];
}


static unsigned to_utf8(unsigned c, char *buf)
{
      unsigned index = 0;

      if (c < 0x80)
            buf[index++] = c;
      else if (c < 0x800) {
            // 110***** 10******
            buf[index++] = 0xc0 | (c >> 6);
            buf[index++] = 0x80 | (c & 0x3f);
      } else if (c < 0x10000) {
            if (c >= 0xD800 && c < 0xE000)
                  return index;
            if (c == 0xFFFF)
                  return index;
            // 1110**** 10****** 10******
            buf[index++] = 0xe0 | (c >> 12);
            buf[index++] = 0x80 | ((c >> 6) & 0x3f);
            buf[index++] = 0x80 | (c & 0x3f);
      } else if (c < 0x200000) {
            // 11110*** 10****** 10****** 10******
            buf[index++] = 0xf0 | (c >> 18);
            buf[index++] = 0x80 | ((c >> 12) & 0x3f);
            buf[index++] = 0x80 | ((c >> 6) & 0x3f);
            buf[index++] = 0x80 | (c & 0x3f);
      }

      return index;
}


char *keysym_to_term_string(unsigned short keysym, char down)
{
      static struct kbsentry kse;
      char *buf = (char *)kse.kb_string;
      *buf = 0;

      if (KTYP(keysym) != KT_SHIFT && !down) return buf;

      keysym = keypad_keysym_redirect(keysym);
      unsigned index = 0, value = KVAL(keysym);


      switch (KTYP(keysym)) {
      case KT_LATIN:
            index = to_utf8(value, buf);
            break;

      case KT_FN:
            kse.kb_func = value;
            ioctl(STDIN_FILENO, KDGKBSENT, &kse);
            index = strlen(buf);
            break;

      case KT_SPEC:
            if (keysym == K_ENTER) {
                  buf[index++] = '\r';
                  if (cr_with_lf) buf[index++] = '\n';
            } else if (keysym == K_NUM && applic_keypad) {
                  buf[index++] = '\e';
                  buf[index++] = 'O';
                  buf[index++] = 'P';
            }
            break;

      case KT_PAD:
            if (applic_keypad && !shift_down[KG_SHIFT]) {
                  if (value < NR_PAD) {
                        static const char app_map[] = "pqrstuvwxylSRQMnnmPQS";

                        buf[index++] = '\e';
                        buf[index++] = 'O';
                        buf[index++] = app_map[value];
                  }
            } else if (keysym == K_P5 && !(lock_state & K_NUMLOCK)) {
                  buf[index++] = '\e';
                  buf[index++] = (applic_keypad ? 'O' : '[');
                  buf[index++] = 'G';
            }
            break;

      case KT_CUR:
            if (value < 4) {
                  static const char cur_chars[] = "BDCA";

                  buf[index++] = '\e';
                  buf[index++] = (cursor_esco ? 'O' : '[');
                  buf[index++] = cur_chars[value];
            }
            break;

      case KT_META: {
            long flag;
            ioctl(STDIN_FILENO, KDGKBMETA, &flag);

            if (flag == K_METABIT) {
                  buf[index++] = 0x80 | value;
            } else {
                  buf[index++] = '\e';
                  buf[index++] = value;
            }
            break;
      }

      case KT_SHIFT:
            if (!down && npadch != -1) {
                  index = to_utf8(npadch, buf);
                  npadch = -1;
            }
            break;
      
      case KT_ASCII:
            if (value < NR_ASCII) {
                  int base = 10;

                  if (value >= KVAL(K_HEX0)) {
                        base = 16;
                        value -= KVAL(K_HEX0);
                  }
                  
                  if (npadch == -1) npadch = value;
                  else npadch = npadch * base + value;
            }
            break;

      default:
            break;
      }

      buf[index] = 0;
      return buf;
}

Generated by  Doxygen 1.6.0   Back to index