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

touchkeyboard.cpp

/* ScummVM - Graphic Adventure Engine
 *
 * ScummVM is the legal property of its developers, whose names
 * are too numerous to list here. Please refer to the COPYRIGHT
 * file distributed with this source distribution.
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */
#include <nds.h>
#include "NDS/scummvm_ipc.h"
#include "touchkeyboard.h"
#include "keyboard_raw.h"
#include "keyboard_pal_raw.h"
#include "8x8font_tga_raw.h"
#include "dsmain.h"
#include "osystem_ds.h"

namespace DS {

struct key_data {
      char keyNum;
      signed char x, y;
      int character;
      bool pressed;
};

#define DS_NUM_KEYS 72
#define DS_SHIFT 2
#define DS_BACKSPACE 8
#define DS_RETURN 13
#define DS_CAPSLOCK 1


static key_data keys[DS_NUM_KEYS] = {
      // Key number           x           y           character

      // Numbers
      {28,                    3,          0,          '1', false},
      {29,                    5,          0,          '2', false},
      {30,                    7,          0,          '3', false},
      {31,                    9,          0,          '4', false},
      {32,                    11,         0,          '5', false},
      {33,                    13,         0,          '6', false},
      {34,                    15,         0,          '7', false},
      {35,                    17,         0,          '8', false},
      {36,                    19,         0,          '9', false},
      {27,                    21,         0,          '0', false},
      {45,                    23,         0,          Common::KEYCODE_MINUS, false},
      {50,                    25,         0,          Common::KEYCODE_EQUALS, false},
      {52,                    27,         0,          Common::KEYCODE_BACKSPACE, false},

      // Top row
      {'Q'-'A' + 1,           4,          2,          'Q', false},
      {'W'-'A' + 1,           6,          2,          'W', false},
      {'E'-'A' + 1,           8,          2,          'E', false},
      {'R'-'A' + 1,           10,         2,          'R', false},
      {'T'-'A' + 1,           12,         2,          'T', false},
      {'Y'-'A' + 1,           14,         2,          'Y', false},
      {'U'-'A' + 1,           16,         2,          'U', false},
      {'I'-'A' + 1,           18,         2,          'I', false},
      {'O'-'A' + 1,           20,         2,          'O', false},
      {'P'-'A' + 1,           22,         2,          'P', false},
      {43,                    24,         2,          Common::KEYCODE_LEFTBRACKET, false},
      {44,                    26,         2,          Common::KEYCODE_RIGHTBRACKET, false},

      // Middle row
      {55,                    3,          4,          DS_CAPSLOCK, false},
      {'A'-'A' + 1,           5,          4,          'A', false},
      {'S'-'A' + 1,           7,          4,          'S', false},
      {'D'-'A' + 1,           9,          4,          'D', false},
      {'F'-'A' + 1,           11,         4,          'F', false},
      {'G'-'A' + 1,           13,         4,          'G', false},
      {'H'-'A' + 1,           15,         4,          'H', false},
      {'J'-'A' + 1,           17,         4,          'J', false},
      {'K'-'A' + 1,           19,         4,          'K', false},
      {'L'-'A' + 1,           21,         4,          'L', false},
      {42,                    23,         4,          Common::KEYCODE_SEMICOLON, false},
      {41,                    25,         4,          Common::KEYCODE_QUOTE, false},
      {46,                    27,         4,          Common::KEYCODE_RETURN, false},

      // Bottom row
      {51,                    4,          6,          DS_SHIFT, false},
      {'Z'-'A' + 1,           6,          6,          'Z', false},
      {'X'-'A' + 1,           8,          6,          'X', false},
      {'C'-'A' + 1,           10,         6,          'C', false},
      {'V'-'A' + 1,           12,         6,          'V', false},
      {'B'-'A' + 1,           14,         6,          'B', false},
      {'N'-'A' + 1,           16,         6,          'N', false},
      {'M'-'A' + 1,           18,         6,          'M', false},
      {38,                    20,         6,          Common::KEYCODE_COMMA, false},
      {39,                    22,         6,          Common::KEYCODE_PERIOD, false},
      {40,                    24,         6,          Common::KEYCODE_SLASH, false},

      // Space bar
      {47,                    9,          8,          Common::KEYCODE_SPACE, false},
      {48,                    11,         8,          Common::KEYCODE_SPACE, false},
      {48,                    13,         8,          Common::KEYCODE_SPACE, false},
      {48,                    15,         8,          Common::KEYCODE_SPACE, false},
      {48,                    17,         8,          Common::KEYCODE_SPACE, false},
      {49,                    19,         8,          Common::KEYCODE_SPACE, false},

      // Cursor arrows
      {52,                    27,         8,          Common::KEYCODE_LEFT, false},
      {54,                    29,         8,          Common::KEYCODE_DOWN, false},
      {53,                    31,         8,          Common::KEYCODE_RIGHT, false},
      {51,                    29,         6,          Common::KEYCODE_UP, false},

      // Close button
      {56,                    30,         0,          Common::KEYCODE_INVALID, false},

      // Function keys (needed for AGI)
      {57,                    4,          -2,         Common::KEYCODE_F1, false},
      {58,                    6,          -2,         Common::KEYCODE_F2, false},
      {59,                    8,          -2,         Common::KEYCODE_F3, false},
      {60,                    10,         -2,         Common::KEYCODE_F4, false},
      {61,                    14,         -2,         Common::KEYCODE_F5, false},
      {62,                    16,         -2,         Common::KEYCODE_F6, false},
      {63,                    18,         -2,         Common::KEYCODE_F7, false},
      {64,                    20,         -2,         Common::KEYCODE_F8, false},
      {65,                    24,         -2,         Common::KEYCODE_F9, false},
      {66,                    26,         -2,         Common::KEYCODE_F10, false},
      {67,                    28,         -2,         Common::KEYCODE_F11, false},
      {68,                    30,         -2,         Common::KEYCODE_F12, false},

};

static int keyboardX;
static int keyboardY;

static int s_mapBase;
static int s_tileBase;

static u16 *baseAddress;

static bool shiftState;
static bool capsLockState;

static bool closed;

static char autoCompleteWord[NUM_WORDS][32];
static int autoCompleteCount;

static char autoCompleteBuffer[128];

static int selectedCompletion = -1;
static int charactersEntered = 0;
static int typingTimeout = 0;

// Render text onto the tiled screen

void drawText(int tx, int ty, const char *string, bool highlight) {

      u16 baseValue = 0;

      if (highlight) {
            baseValue |= 0x1000;
      }

      for (int p = 0; *string; string++, p++) {
            char c = *string;

            if (c != ' ') {
                  int tile = c - 33 + (KEYBOARD_DATA_SIZE / 32);
                  baseAddress[ty * 32 + tx + p] = baseValue | tile;
            }
      }
      
}



void restoreVRAM(int tileBase, int mapBase, u16 *saveSpace) {
/*    for (int r = 0; r < 32 * 32; r++) {
            ((u16 *) SCREEN_BASE_BLOCK_SUB(mapBase))[r] = *saveSpace++;
      }

      for (int r = 0; r < 4096; r++) {
            ((u16 *) CHAR_BASE_BLOCK_SUB(tileBase))[r]      = *saveSpace++;
      }*/
}

void drawKeyboard(int tileBase, int mapBase, u16 *saveSpace) {
      /* int keyboardDataSize = 4736 * 2; */

      for (int r = 0; r < 32 * 32; r++) {
//          *saveSpace++ = ((u16 *) SCREEN_BASE_BLOCK_SUB(mapBase))[r];
            ((u16 *) SCREEN_BASE_BLOCK_SUB(mapBase))[r] = 0;
      }

      for (int r = 0; r < KEYBOARD_DATA_SIZE / 2; r++) {
//          *saveSpace++ = ((u16 *) CHAR_BASE_BLOCK_SUB(tileBase))[r];
            ((u16 *) CHAR_BASE_BLOCK_SUB(tileBase))[r] = ((u16 *) (::keyboard_raw))[r];
      }

      for (int r = 0; r < 16; r++) {
            BG_PALETTE_SUB[r] = ((u16 *) (keyboard_pal_raw))[r];
      }

      // this is the font
      for (int tile = 0; tile < 94; tile++) {

            u16 *tileAddr = (u16 *) (CHAR_BASE_BLOCK_SUB(tileBase) + ((KEYBOARD_DATA_SIZE) + (tile * 32)));
            const u8 *src = ((const u8 *) (::_8x8font_tga_raw)) + 18 + tile * 8;

            for (int y = 0 ; y < 8; y++) {
                  for (int x = 0; x < 2; x++) {
                         *(tileAddr + (y * 2) + x) =(*(src + (y * 752) + (x * 4) + 0) & 0x0F)
                                                             | ((*(src + (y * 752) + (x * 4) + 1) & 0x0F) << 4)
                                                             | ((*(src + (y * 752) + (x * 4) + 2) & 0x0F) << 8)
                                                             | ((*(src + (y * 752) + (x * 4) + 3) & 0x0F) << 12);

                  }
            }
      }




      for (int r = 0; r < 16; r++) {
            int col = ((u16 *) (keyboard_pal_raw))[r];

            int red = col & 0x001F;
            int green = (col & 0x03E0) >> 5;
            int blue = (col & 0x7C00) >> 10;

            red = (red * 8) / 16;
            green = (green * 24) / 16;
            blue = (blue * 8) / 16;

            if (green > 31) green = 31;

            BG_PALETTE_SUB[16 + r] = red | (green << 5) | (blue << 10);
      }

      keyboardX = -2;
      keyboardY = 2;

      DS::s_mapBase = mapBase;
      DS::s_tileBase = tileBase;

      shiftState = false;
      capsLockState = false;

      int x = keyboardX;
      int y = keyboardY;

      u16 *base = ((u16 *) SCREEN_BASE_BLOCK_SUB(mapBase));
      baseAddress = base;

      for (int r = 0; r < DS_NUM_KEYS; r++) {
            base[(y + keys[r].y) * 32 + x + keys[r].x] = 10 + keys[r].keyNum * 2;
            base[(y + keys[r].y) * 32 + x + keys[r].x + 1] = 10 + keys[r].keyNum * 2 + 1;

            base[(y + keys[r].y + 1) * 32 + x + keys[r].x] = 10 + 148 + keys[r].keyNum * 2;
            base[(y + keys[r].y + 1) * 32 + x + keys[r].x + 1] = 10 + 148 + keys[r].keyNum * 2 + 1;

            keys[r].pressed = false;
      }


      closed = false;
      clearAutoComplete();

}


void drawAutoComplete() {

      // Clear the auto complete area at the bottom of the screen.
      for (int y = 12; y < 24; y++) {
            for (int x = 0; x < 32; x++) {
                  baseAddress[y * 32 + x] = 0;
            }
      }


      if ((autoCompleteCount == 0) || (typingTimeout > 0)) {

            // When there's no completions on the bottom of the screen, it acts like a mouse pad
            // so this text indicates that
            drawText(11, 18, "MOUSE AREA", true);
            

      } else {

            consolePrintf("time: %d\n", typingTimeout);

            // Otherwise, draw autocompletions if one isn't being entered and there are
            // some available.
            for (int r = 0; r < autoCompleteCount; r++) {
                  int y = 12 + (r % 6) * 2;
                  int x = 0 + ((r / 6) * 16);
      
                  drawText(x, y, autoCompleteWord[r], selectedCompletion == r);
            }
      
      }
}

bool getKeyboardClosed() {
      return closed;
}

void setKeyHighlight(int key, bool highlight) {
      u16 *base = ((u16 *) SCREEN_BASE_BLOCK_SUB(DS::s_mapBase));

      if (highlight) {
            base[(keyboardY + keys[key].y) * 32 + keyboardX + keys[key].x] |= 0x1000;
            base[(keyboardY + keys[key].y) * 32 + keyboardX + keys[key].x + 1] |= 0x1000;
            base[(keyboardY + keys[key].y + 1) * 32 + keyboardX + keys[key].x] |= 0x1000;
            base[(keyboardY + keys[key].y + 1) * 32 + keyboardX + keys[key].x + 1] |= 0x1000;
      } else {
            base[(keyboardY + keys[key].y) * 32 + keyboardX + keys[key].x] &= ~0x1000;
            base[(keyboardY + keys[key].y) * 32 + keyboardX + keys[key].x + 1] &= ~0x1000;
            base[(keyboardY + keys[key].y + 1) * 32 + keyboardX + keys[key].x] &= ~0x1000;
            base[(keyboardY + keys[key].y + 1) * 32 + keyboardX + keys[key].x + 1] &= ~0x1000;
      }
}

void addAutoComplete(const char *word) {
      if (autoCompleteCount == NUM_WORDS) return;
      strcpy(&autoCompleteWord[autoCompleteCount++][0], word);
      drawAutoComplete();
}

void setCharactersEntered(int count) {
      charactersEntered = count;
}

bool isInsideKeyboard(int x, int y) {
      // When completions are available, keyboard covers the whole screen.
      // otherwise, it only covers the area above KEYBOARD_BOTTOM_Y
      return (autoCompleteCount > 0) || (y < KEYBOARD_BOTTOM_Y);
}

void clearAutoComplete() {
      autoCompleteCount = 0;
      selectedCompletion = -1;
      drawAutoComplete();
}

void typeCompletion(int current) {
      Common::Event event;
      /* OSystem_DS *system = OSystem_DS::instance(); */

      strcat(autoCompleteBuffer, &autoCompleteWord[current][charactersEntered]);
      strcat(autoCompleteBuffer, " ");

/*    consolePrintf("Typing word: %s\n", autoCompleteWord[current]);

      for (int r = charactersEntered; r < strlen(autoCompleteWord[current]); r++) {
            event.kbd.keycode = autoCompleteWord[current][r];
            event.kbd.ascii = autoCompleteWord[current][r];
            event.type = Common::EVENT_KEYDOWN;
            event.kbd.flags = 0;
            system->addEvent(event);

            event.type = Common::EVENT_KEYUP;
            system->addEvent(event);
      }

      event.kbd.keycode = ' ';
      event.kbd.ascii = ' ';

      event.type = Common::EVENT_KEYDOWN;
      system->addEvent(event);

      event.type = Common::EVENT_KEYUP;
      system->addEvent(event);*/
}

void updateTypeEvents() {
      if (autoCompleteBuffer[0] != '\0') {
            Common::Event event;
            OSystem_DS *system = OSystem_DS::instance();

            event.kbd.keycode = (Common::KeyCode) autoCompleteBuffer[0];
            event.kbd.ascii = autoCompleteBuffer[0];
            event.type = Common::EVENT_KEYDOWN;
            event.kbd.flags = 0;
            system->addEvent(event);

            event.type = Common::EVENT_KEYUP;
            system->addEvent(event);

            for (int r = 0; r < (int)strlen(autoCompleteBuffer); r++) {
                  autoCompleteBuffer[r] = autoCompleteBuffer[r + 1];
            }

            typingTimeout = 100;
      }
}

void createKeyEvent(int keyNum, Common::Event& event) {
      event.kbd.flags = 0;

      if ((keys[keyNum].character >= '0') && (keys[keyNum].character <= '9')) {

            if (!DS::shiftState) {
                  event.kbd.ascii = keys[keyNum].character;
                  event.kbd.keycode = (Common::KeyCode) keys[keyNum].character; //Common::KEYCODE_INVALID;
            } else {
                  event.kbd.keycode = (Common::KeyCode) (Common::KEYCODE_F1 - (keys[keyNum].character - '1'));
                  event.kbd.ascii = 0;
            }

      } else if ((keys[keyNum].character >= 'A') && (keys[keyNum].character <= 'Z')) {

            if ((!DS::shiftState) && (!DS::capsLockState)) {
                  event.kbd.ascii = keys[keyNum].character + 32; // Make key lowercase.
            } else {
                  event.kbd.ascii = keys[keyNum].character;
            }

            event.kbd.keycode = (Common::KeyCode) event.kbd.ascii;
      } else {
            if ((keys[keyNum].character >= Common::KEYCODE_F1) && (keys[keyNum].character >= Common::KEYCODE_F12))      {
                  event.kbd.keycode = (Common::KeyCode) keys[keyNum].character;
                  event.kbd.ascii = keys[keyNum].character - Common::KEYCODE_F1 + Common::ASCII_F1;
            } else {
                  event.kbd.ascii = keys[keyNum].character;
                  event.kbd.keycode = (Common::KeyCode) keys[keyNum].character;
            }
      }
}

void releaseAllKeys() {
      for (int r = 0; r < DS_NUM_KEYS; r++) {
            if (keys[r].pressed) {
                  DS::setKeyHighlight(r, false);

                  OSystem_DS *system = OSystem_DS::instance();

                  Common::Event event;
                  createKeyEvent(r, event);
                  event.type = Common::EVENT_KEYUP;
                  system->addEvent(event);

                  keys[r].pressed = false;
            }
      }
}

void addKeyboardEvents() {
      bool resetShift = false;

      updateTypeEvents();

      if (typingTimeout > 0) {
            typingTimeout--;
            if (typingTimeout == 0) {
                  drawAutoComplete();
            }
      }

      if (DS::getPenDown()) {
            int x = IPC->touchXpx;
            int y = IPC->touchYpx;

            int tx = (x >> 3);
            int ty = (y >> 3);

            if (ty >= 12) {
                  int current = -1;

                  if (tx < 12) {
                        current = (ty - 12) / 2;
                  } else {
                        current = 6 + (ty - 12) / 2;
                  }

                  if (selectedCompletion == current) {
                        typeCompletion(current);
                  } else {
                        if (current < autoCompleteCount) {
                              selectedCompletion = current;
                        }
                  }

                  drawAutoComplete();
            }

            tx -= keyboardX;
            ty -= keyboardY;

//          consolePrintf("x=%d y=%d\n", tx, ty);

            for (int r = 0; r < DS_NUM_KEYS; r++) {
                  if (( (tx >= keys[r].x) && (tx <= keys[r].x + 1)) &&
                           (ty >= keys[r].y) && (ty <= keys[r].y + 1)) {
                        OSystem_DS *system = OSystem_DS::instance();
                        Common::Event event;

//                      consolePrintf("Key: %d\n", r);
                        if ((keys[r].character == Common::KEYCODE_INVALID)) {
                              // Close button
                              //DS::closed = true;
                        } else {
                              createKeyEvent(r, event);
                        }

                        //event.kbd.keycode = keys[r].character;
                        //event.kbd.ascii = keys[r].character;
                        event.type = Common::EVENT_KEYDOWN;
                        system->addEvent(event);

//                      event.type = Common::EVENT_KEYUP;
//                      system->addEvent(event);

                        switch (keys[r].character) {
                              case DS_SHIFT: {
                                    DS::shiftState = !DS::shiftState;
                                    DS::setKeyHighlight(r, DS::shiftState);
                                    break;
                              }

                              case DS_CAPSLOCK: {
                                    DS::capsLockState = !DS::capsLockState;
                                    DS::setKeyHighlight(r, DS::capsLockState);
                                    break;
                              }

                              default: {
                                    DS::setKeyHighlight(r, true);
                                    keys[r].pressed = true;
                                    break;
                              }
                        }

                  }
            }
      }

      if (DS::getPenReleased()) {

            for (int r = 0; r < DS_NUM_KEYS; r++) {
                  if (keys[r].pressed) {
                        DS::setKeyHighlight(r, false);

                        OSystem_DS *system = OSystem_DS::instance();

                        Common::Event event;
                        if ((keys[r].character == Common::KEYCODE_INVALID)) {
                              // Close button
                              DS::closed = true;
                        } else {
                              createKeyEvent(r, event);
                              event.type = Common::EVENT_KEYUP;
                              system->addEvent(event);
                        }

                        keys[r].pressed = false;

                        if (keys[r].character != DS_SHIFT) {
                              resetShift = true;
                        }
                  }
            }

      }


      if ((resetShift) && (DS::shiftState)) {
            DS::shiftState = false;
            resetShift = false;
            for (int t = 0; t < DS_NUM_KEYS; t++) {
                  if (keys[t].character == DS_SHIFT) {
                        DS::setKeyHighlight(t, false);
                  }
            }
      }

}

}     // End of namespace DS

Generated by  Doxygen 1.6.0   Back to index