/* Mednafen - Multi-system Emulator
 *
 * 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 "main.h"

static bool NeedInit = 1;
static bool WatchLogical = 1; // Watch logical memory addresses, not physical
static bool IsActive = 0;

static std::string ReadBreakpoints;
static std::string WriteBreakpoints;

static void ParseBreakpoints(const std::string &Breakpoints, int type)
{
 LockDebuggerMutex(1);

 size_t len = Breakpoints.size();
 const char *zestring = Breakpoints.c_str();
 int last_x, x;
 bool two_parter = 0;
 bool logical = 1;

 CurGame->Debugger->FlushBreakPoints(type);

 for(last_x = x = 0; x < len; x++)
 {
  if(zestring[x] == '-')
   two_parter = 1;
  else if(zestring[x] == '*')
  {
   logical = 0;
   last_x++;
  }
  else if(zestring[x] == ' ' || x == len - 1)
  {
   uint32 A1, A2;

   if(two_parter)
   {
    if(sscanf(zestring + last_x, "%08x%*[-]%08x", &A1, &A2) < 2) continue;
   }
   else
   {
    if(sscanf(zestring + last_x, "%08x", &A1) != 1) continue;
    A2 = A1;
   }
   //printf("%04x %04x %d\n", A1, A2, logical);
   CurGame->Debugger->AddBreakPoint(type, A1, A2, logical);
   last_x = x + 1;
   logical = 1;
  }
 }
 LockDebuggerMutex(0);
}

static unsigned int RegsPos = 0;
static uint32 InRegs = 0;
static uint32 RegsCols = 0;
static uint32 RegsColsCounts[4];

#define MK_COLOR_A(r,g,b,a) ( ((a)<<surface->format->Ashift) | ((r)<<surface->format->Rshift) | ((g) << surface->format->Gshift) | ((b) << surface->format->Bshift))
#define DIS_ENTRIES	24

uint32 DrawTextTrans(uint32 *dest, int pitch, uint32 width, uint8 *textmsg, uint32 fgcolor, int centered, bool);

static std::vector<uint32> PCBreakPoints;
static void RedoPCBreakPoints(void)
{
 LockDebuggerMutex(1);
 CurGame->Debugger->FlushBreakPoints(BPOINT_PC);

 for(unsigned int x = 0; x < PCBreakPoints.size(); x++)
 {
  CurGame->Debugger->AddBreakPoint(BPOINT_PC, PCBreakPoints[x], PCBreakPoints[x], 1);
 }
 LockDebuggerMutex(0);
}

static INLINE bool IsPCBreakPoint(uint32 A)
{
 unsigned int max = PCBreakPoints.size();

 for(unsigned int x = 0; x < max; x++)
  if(PCBreakPoints[x] == A)
   return(1);
 return(0);
}

static void TogglePCBreakPoint(uint32 A)
{
 for(unsigned int x = 0; x < PCBreakPoints.size(); x++)
 {
  if(PCBreakPoints[x] == A)
  {
   PCBreakPoints.erase(PCBreakPoints.begin() + x);
   RedoPCBreakPoints();
   return;
  }
 }
 PCBreakPoints.push_back(A);
 RedoPCBreakPoints();
}


static uint32 WatchAddr = 0x0000, WatchAddrPhys = 0x0000;
static uint32 DisAddr = 0x0000;
static int NeedDisAddrChange = 0;

static bool NeedPCBPToggle = 0;
static volatile int NeedStep = 0;
static volatile int NeedRun = 0;
static bool NeedBreak = 0;
static bool InSteppingMode = 0;

static void DrawRegs(RegType *rec, SDL_Surface *surface, uint32 *pixels, int highlight)
{
  uint32 pitch32 = surface->pitch >> 2;
  uint32 *row = pixels;
  unsigned int meowcow = 0;

  while(rec->bsize)
  {
   char nubuf[256];
   uint32 color = MK_COLOR_A(0xFF, 0xFF, 0xFF, 0xFF);

   if(highlight == meowcow)
    color = MK_COLOR_A(0xFF, 0x00, 0x00, 0xFF);

   DrawTextTrans(row - rec->name.size() * 5, surface->pitch, 128, (UTF8*)rec->name.c_str(), color, 0, 1);

   if(rec->bsize == 2)
    snprintf(nubuf, 256, ": %04X", CurGame->Debugger->GetRegister(rec->name));
   else if(rec->bsize == 1)
    snprintf(nubuf, 256, ": %02X", CurGame->Debugger->GetRegister(rec->name));

   DrawTextTrans(row, surface->pitch, 64, (UTF8*)nubuf, color, 0, 1);
   row += 7 * pitch32;
   rec++;
   meowcow++;
  }
}

typedef enum
{
 None = 0,
 DisGoto,
 WatchGoto,
 EditRegs0,
 EditRegs1,
 EditRegs2,
 PokeMe,
 PokeMeHL,
 ReadBPS,
 WriteBPS,
 DumpMem,
 DumpGfxMem,
} PromptType;

static PromptType InPrompt = None;
static std::string PromptText = "";
static std::vector<std::string> kb_buffer;
static int kb_cursor_pos = 0;

static void DrawPrompt(SDL_Surface *surface, const SDL_Rect *rect)
{
 std::string PromptAnswer;

 for(unsigned int i = 0; i < kb_buffer.size(); i++)
  PromptAnswer += kb_buffer[i];

/*
******************************
* PC                         *
* F00F                       *
******************************
*/
 uint32 *pixels = (uint32 *)surface->pixels;
 uint32 pitch32 = surface->pitch >> 2;

 pixels += ((rect->h / 2) - (4 * 7 / 2)) * pitch32;
 pixels += ((rect->w / 2) - (5 * 39 / 2));

 for(unsigned int y = 0; y < 4 * 7; y++)
 {
  uint32 *row = pixels + y * pitch32;
  for(unsigned int x = 0; x < 39 * 5; x++)
   row[x] = MK_COLOR_A(0, 0, 0, 0xFF);
 }

 DrawTextTrans(pixels, surface->pitch, 39 * 5, (UTF8 *)"**************************************", MK_COLOR_A(0xFF,0xFF,0xFF,0xFF), 0, 1);
 DrawTextTrans(pixels + 7 * pitch32, surface->pitch, 39 * 5, (UTF8 *)"*                                    *", MK_COLOR_A(0xFF,0xFF,0xFF,0xFF), 0, 1);
 DrawTextTrans(pixels + 14 * pitch32, surface->pitch, 39 * 5, (UTF8 *)"*                                    *", MK_COLOR_A(0xFF,0xFF,0xFF,0xFF), 0, 1);
 DrawTextTrans(pixels + 21 * pitch32, surface->pitch, 39 * 5, (UTF8 *)"**************************************", MK_COLOR_A(0xFF,0xFF,0xFF,0xFF), 0, 1);

 DrawTextTrans(pixels + 7 * pitch32 + 2 * 5, surface->pitch, (39 - 4) * 5, (UTF8 *)PromptText.c_str(), MK_COLOR_A(0xFF, 0x00, 0xFF, 0xFF), 0, 1);
 DrawTextTrans(pixels + 14 * pitch32 + 2 * 5, surface->pitch, (39 - 4) * 5, (UTF8 *)PromptAnswer.c_str(), MK_COLOR_A(0x00, 0xFF, 0x00, 0xFF), 0, 1);

 if((SDL_GetTicks() & 0x80) && kb_cursor_pos < (39 - 4))
  DrawTextTrans(pixels + 14 * pitch32 + 2 * 5 + kb_cursor_pos * 5, surface->pitch, 5, (UTF8*)"▉", MK_COLOR_A(0x00, 0xFF, 0x00, 0xFF), 0, 1);
}



// Call this function from the main thread
void Debugger_Draw(SDL_Surface *surface, const SDL_Rect *rect)
{
 if(!IsActive) return;

 uint32 * pixels = (uint32 *)surface->pixels;
 uint32 pitch32 = surface->pitch >> 2;

 for(unsigned int y = 0; y < rect->h; y++)
 {
  uint32 *row = pixels + y * pitch32;
  for(unsigned int x = 0; x < rect->w; x++)
  {
   //printf("%d %d %d\n", y, x, pixels);
   row[x] = MK_COLOR_A(0, 0, 0, 0xc0);
   //row[x] = MK_COLOR_A(0x00, 0x00, 0x00, 0x7F);
  }
 }

 LockDebuggerMutex(1);

 // We need to disassemble (maximum_instruction_size * 12 * 3)
 // bytes to make sure we can center our desired DisAddr, and
 // that we have enough disassembled datums for displayaling and
 // worshipping cactus mules.

 int PreBytes = CurGame->Debugger->MaxInstructionSize * 12 * 2;
 int DisBytes = CurGame->Debugger->MaxInstructionSize * 12 * 3;

 uint32 A = (DisAddr - PreBytes) & 0xFFFF;
 std::vector<std::string> DisBliss;
 std::vector<uint32> DisBlissA;
 int indexcow = 0;

 while(DisBytes > 0)
 {
  uint32 lastA = A;

  if(A == DisAddr)
   indexcow = DisBliss.size();

  DisBlissA.push_back(A);
  DisBliss.push_back(CurGame->Debugger->Disassemble(A, DisAddr)); // A is passed by reference to Disassemble()

  if(A > DisAddr && lastA < DisAddr) // Err, oops, resynch to DisAddr if necessary
  {
   A = DisAddr;
  }

  int64 consumed = (int64)A - lastA;  

  if(consumed < 0)
  {
   consumed += 1ULL << 16;
  }
  DisBytes -= consumed;
 }
 
 for(int x = 0; x < DIS_ENTRIES; x++)
 {
  std::string dis_str = DisBliss[indexcow - 12 + x];
  uint32 A = DisBlissA[indexcow - 12 + x];
  char mootext[256];

  uint32 color = MK_COLOR_A(0xFF, 0xFF, 0xFF, 0xFF);

  snprintf(mootext, 256, "  %04X: %s", A, dis_str.c_str());
  
  if(A == DisAddr)
  {
   mootext[0] = '>';
   if(!InRegs)
    color = MK_COLOR_A(0xFF, 0x00, 0x00, 0xFF);

   if(NeedPCBPToggle)
   {
    TogglePCBreakPoint(A);
    NeedPCBPToggle = 0;
   }

  }
  if(IsPCBreakPoint(A))
   mootext[1] = '*';

  DrawTextTrans(pixels + x * 7 * pitch32, surface->pitch, rect->w, (UTF8*)mootext, color, 0, 1);
 }

 if(NeedDisAddrChange)
 {
  DisAddr = DisBlissA[indexcow + NeedDisAddrChange];
  NeedDisAddrChange = 0;
 }

 if(CurGame->Debugger->Regs[0])
  DrawRegs(CurGame->Debugger->Regs[0], surface, pixels + rect->w - 175, (InRegs == 1) ? (int)RegsPos : -1); // 175

 if(CurGame->Debugger->Regs[1]) // 111
  DrawRegs(CurGame->Debugger->Regs[1], surface, pixels + rect->w - 111, (InRegs == 2) ? (int)RegsPos : -1);
 
 if(CurGame->Debugger->Regs[2]) // 32
  DrawRegs(CurGame->Debugger->Regs[2], surface, pixels + rect->w - 32, (InRegs == 3) ? (int)RegsPos : -1);

 if(CurGame->Debugger->GetBranchTrace)
 {
  std::vector<uint32> btrace = CurGame->Debugger->GetBranchTrace();
  uint32 *btpixels = pixels + (24 * 7) * pitch32 + rect->w - 16 * 5;

  for(int y = 0; y < 8; y++)
  {
   uint32 *row = btpixels + y * pitch32 * 7;
   char buf[64];
   snprintf(buf, 64, "%04X", btrace[y]);
   DrawTextTrans(row, surface->pitch, 16 * 5, (UTF8*)buf, MK_COLOR_A(0xFF, 0xFF, 0xFF, 0xFF), 0, 1);
  } 
 }

 {
  uint32 *watchpixels = pixels + ((24 * 7)) * pitch32;
 
  for(int y = 0; y < 8; y++)
  {
   uint32 *row = watchpixels + y * pitch32 * 7;
   char tbuf[256];
   char asciistr[16 + 1];
   uint32 ewa;
   uint32 ewa_bits;
   uint32 ewa_mask;

   asciistr[16] = 0;  

   if(WatchLogical)
   {
    ewa_bits = CurGame->Debugger->LogAddrBits;
    ewa = WatchAddr;
   }
   else
   {
    ewa_bits = CurGame->Debugger->PhysAddrBits;
    ewa = WatchAddrPhys;
   }
   
   ewa_mask = ((uint64)1 << ewa_bits) - 1;

   if(ewa_bits <= 16)
    snprintf(tbuf, 256, "%04X: ", (ewa + y * 16) & ewa_mask);
   else if(ewa_bits <= 24)
    snprintf(tbuf, 256, "%06X: ", (ewa + y * 16) & ewa_mask);
   else
    snprintf(tbuf, 256, "%08X: ", (ewa + y * 16) & ewa_mask);

   row += DrawTextTrans(row, surface->pitch, rect->w, (UTF8 *)tbuf, MK_COLOR_A(0xFF, 0xFF, 0xFF, 0xFF), 0, 1);
   for(int x = 0; x < 16; x++)
   {
    uint8 zebyte = CurGame->Debugger->MemPeek((ewa + y * 16 + x) & ewa_mask, 1, 1, WatchLogical);
    asciistr[x] = zebyte;
    if(zebyte & 0x80 || !zebyte)
     asciistr[x] = '.';
    snprintf(tbuf, 256, "%02X", zebyte);
    row += DrawTextTrans(row, surface->pitch, rect->w, (UTF8*)tbuf, MK_COLOR_A(0xFF, 0xFF, 0xFF, 0xFF), 0, 1) + 6;
   }
   DrawTextTrans(row, surface->pitch, rect->w, (UTF8 *)asciistr, MK_COLOR_A(0xFF, 0xFF, 0xFF, 0xFF), 0, 1);
  }
 }  

 if(InPrompt)
  DrawPrompt(surface, rect);

 LockDebuggerMutex(0);
}

// Function called from game thread
static void CPUCallback(uint32 PC)
{
 if((NeedStep == 2 && !InSteppingMode) || NeedBreak)
 {
  DisAddr = PC;
  NeedStep = 0;
  InSteppingMode = 1;
  NeedBreak = 0;
 }

 if(NeedStep == 1)
 {
  DisAddr = PC;
  NeedStep = 0;
 }

 while(InSteppingMode && GameThreadRun)
 {
  DebuggerFudge();
  if(NeedStep == 2)
  {
   NeedStep--;
   break;
  }
  if(NeedRun)
  {
   NeedStep = 0;
   NeedRun = 0;
   InSteppingMode = 0;
  }
 }
 if(NeedRun) NeedRun = 0;
}

// Function called from game thread
static void BPCallback(uint32 PC)
{
 NeedBreak = 1;
 IsActive = 1;
}

// Function called from game thread, input driver code.
void Debugger_ForceStepIfStepping(void)
{
 if(InSteppingMode)
  NeedStep = 2;
}

// Call this function from any thread:
bool Debugger_IsActive(void)
{
 return(IsActive);
}


// Call this function from the game thread:
bool Debugger_Toggle(void)
{
 if(CurGame->Debugger)
 {
  if(NeedInit)
  {
   NeedInit = 0;
   CurGame->Debugger->SetCPUCallback(CPUCallback);
   CurGame->Debugger->SetBPCallback(BPCallback);
   WatchAddr = CurGame->Debugger->DefaultWatchAddr;
   DisAddr = CurGame->Debugger->GetRegister("PC");

   RegsCols = 0;
   memset(RegsColsCounts, 0, sizeof(RegsColsCounts));

   for(int r = 0; r < 3; r++)
   {
    if(CurGame->Debugger->Regs[r])
    {
     for(int x = 0; CurGame->Debugger->Regs[r][x].bsize; x++)
      RegsColsCounts[r]++;
     RegsCols++;
    }
   }
  }
  IsActive = !IsActive;
 }
 return(IsActive);
}


#include "../ConvertUTF.h"

int Debugger_Event(const SDL_Event *event)
{
  switch(event->type)
  {
   case SDL_KEYDOWN:
	if(event->key.keysym.mod & KMOD_ALT)
         break;

        if(InPrompt)
        {
         switch(event->key.keysym.sym)
         {
          case SDLK_HOME:
                kb_cursor_pos = 0;
                break;
          case SDLK_END:
                kb_cursor_pos = kb_buffer.size();
                break;
	  case SDLK_LEFT:
		if(kb_cursor_pos)
		 kb_cursor_pos--;
		break;
	  case SDLK_RIGHT:
		if(kb_cursor_pos < kb_buffer.size())
		 kb_cursor_pos++;
		break;
          case SDLK_RETURN:
                 {
                  std::string concat_str;
                  for(unsigned int i = 0; i < kb_buffer.size(); i++)
                   concat_str += kb_buffer[i];

                  char *tmp_c_str = strdup(concat_str.c_str());
                  kb_buffer.clear();
		  kb_cursor_pos = 0;

                  if(InPrompt == DisGoto)
                  {
                   sscanf(tmp_c_str, "%08X", &DisAddr);
                   DisAddr &= 0xFFFF;
                  }
		  else if(InPrompt == ReadBPS)
		  {
                   ReadBreakpoints = std::string(tmp_c_str);
                   ParseBreakpoints(ReadBreakpoints, BPOINT_READ);
		  }
		  else if(InPrompt == WriteBPS)
		  {
		   WriteBreakpoints = std::string(tmp_c_str);
		   ParseBreakpoints(WriteBreakpoints, BPOINT_WRITE);
		  }
                  else if(InPrompt == PokeMe)
                  {
                   uint32 A = 0,V = 0,S = 1;
		   bool logical = 1;

		   char *meow_str = tmp_c_str;

		   if(meow_str[0] == '*')
		   {
		    meow_str++;
		    logical = 0;
		   }

                   if(sscanf(tmp_c_str, "%08X %08X %d", &A, &V, &S) >= 2) // Allow size to be omitted, implicit as '1'
		   {
                    A &= 0xFFFF;

                    if(S < 1) S = 1;
                    if(S > 4) S = 4;

		    LockDebuggerMutex(1);
                    CurGame->Debugger->MemPoke(A, V, S, 0, logical);
 		    LockDebuggerMutex(0);
		   }
                  }
                  else if(InPrompt == PokeMeHL)
                  {
                   uint32 A = 0,V = 0,S = 1;
                   bool logical = 1;
 
                   char *meow_str = tmp_c_str;

                   if(meow_str[0] == '*')
                   {
                    meow_str++;
                    logical = 0;
                   }

                   if(sscanf(meow_str, "%08X %08X %d", &A, &V, &S) >= 2) // Allow size to be omitted, implicit as '1'
                   {
                    A &= 0xFFFF;

                    if(S < 1) S = 1;
                    if(S > 4) S = 4;

                    LockDebuggerMutex(1);
                    CurGame->Debugger->MemPoke(A, V, S, 1, logical);
                    LockDebuggerMutex(0);
                   }
                  }
		  else if(InPrompt == DumpMem)
		  {
		   uint32 A1, A2;
		   char fname[64];
		   char *meow_str = tmp_c_str;
		   bool logical = 1;

		   if(meow_str[0] == '*')
		   {
		    meow_str++;
		    logical = 0;
		   }

		   if(sscanf(meow_str, "%08x %08x %63[^\r\n]", &A1, &A2, fname) == 3)
		   {
		    FILE *fp = fopen(fname, "wb");
		    if(fp)
		    {
		     LockDebuggerMutex(1);
		     for(uint64 A = A1; A <= A2; A++)
		     {
		      fputc(CurGame->Debugger->MemPeek(A, 1, 1, logical), fp);
		     }
		     LockDebuggerMutex(0);
		     fclose(fp);
		    }
		   }
		  }
                  else if(InPrompt == DumpGfxMem)
                  {
                   uint32 A1, A2;
                   char fname[64];
                   char *meow_str = tmp_c_str;
                   bool logical = 1;

                   if(meow_str[0] == '*')
                   {
                    meow_str++;
                    logical = 0;
                   }

                   if(sscanf(meow_str, "%08x %08x %63[^\r\n]", &A1, &A2, fname) == 3)
                   {
                    FILE *fp = fopen(fname, "wb");
                    if(fp)
                    {
                     LockDebuggerMutex(1);
                     for(uint64 A = A1; A <= A2; A++)
                     {
                      fputc(CurGame->Debugger->GfxMemPeek(A, 1, 1), fp);
                     }
                     LockDebuggerMutex(0);
                     fclose(fp);
                    }
                   }
                  }
                  else if(InPrompt == EditRegs0 || InPrompt == EditRegs1 || InPrompt == EditRegs2)
                  {
                   uint32 RegValue = 0;

                   sscanf(tmp_c_str, "%08X", &RegValue);
		   LockDebuggerMutex(1);
                   CurGame->Debugger->SetRegister(PromptText, RegValue);
		   LockDebuggerMutex(0);
                  }
                  else if(InPrompt == WatchGoto)
                  {
                   if(WatchLogical)
                   {
                    sscanf(tmp_c_str, "%08X", &WatchAddr);
                    WatchAddr &= 0xFFF0;
                   }
                   else
                   {
                    sscanf(tmp_c_str, "%08X", &WatchAddrPhys);
                    WatchAddrPhys &= (((uint64)1 << CurGame->Debugger->PhysAddrBits) - 1);
                    WatchAddrPhys &= ~0xF;
                   }
                  }
                  free(tmp_c_str);
                  InPrompt = None;
                 }
		 break;
	 case SDLK_ESCAPE:
		InPrompt = None;
		kb_buffer.clear();
		kb_cursor_pos = 0;

		break;
         case SDLK_BACKSPACE:
                if(kb_buffer.size() && kb_cursor_pos)
                {
                  kb_buffer.erase(kb_buffer.begin() + kb_cursor_pos - 1, kb_buffer.begin() + kb_cursor_pos);
		  kb_cursor_pos--;
                }
                break;
	  case SDLK_DELETE:
		if(kb_buffer.size() && kb_cursor_pos < kb_buffer.size())
		{
		 kb_buffer.erase(kb_buffer.begin() + kb_cursor_pos, kb_buffer.begin() + kb_cursor_pos + 1);
		}
		break;
	  default:
	   if(event->key.keysym.unicode)
	   {
            uint8 utf8_buffer[8];
            UTF8 *dest_ptr = utf8_buffer;
            memset(utf8_buffer, 0, sizeof(utf8_buffer));
            const UTF16 *start_utf16 = &event->key.keysym.unicode;
            ConvertUTF16toUTF8(&start_utf16, (UTF16 *)&event->key.keysym.unicode + 1, &dest_ptr, &utf8_buffer[8], lenientConversion);
            kb_buffer.insert(kb_buffer.begin() + kb_cursor_pos, std::string((char *)utf8_buffer));
	    kb_cursor_pos++;
	   }
	   break;
         }
	}
        else switch(event->key.keysym.sym)
        {
	 default: break;
	 case SDLK_HOME:
		DisAddr = 0x0000;
		break;
	 case SDLK_END:
		DisAddr = 0xFFFF;
		break;

         case SDLK_PAGEUP:
          if(event->key.keysym.mod & KMOD_SHIFT)
	  {
	   if(WatchLogical)
            WatchAddr = (WatchAddr - 0x80) & 0xFFFF;
	   else
	    WatchAddrPhys = (WatchAddrPhys - 0x80) & (((uint64)1 << CurGame->Debugger->PhysAddrBits) - 1);
	  }
          else
	   NeedDisAddrChange = -11;
          break;
	 case SDLK_PAGEDOWN: 
          if(event->key.keysym.mod & KMOD_SHIFT) 
	  {
	   if(WatchLogical)
            WatchAddr = (WatchAddr + 0x80) & 0xFFFF; 
	   else
	    WatchAddrPhys = (WatchAddrPhys + 0x80) & (((uint64)1 << CurGame->Debugger->PhysAddrBits) - 1);
	  }
          else  
	   NeedDisAddrChange = 11;
          break;

	case SDLK_m:
	   WatchLogical = !WatchLogical;
	   break;

	case SDLK_LEFT:
		if(!InRegs)
		 InRegs = RegsCols;		
		else
		 InRegs = InRegs - 1;

		if(InRegs && RegsPos >= RegsColsCounts[InRegs - 1])
 		 RegsPos = RegsColsCounts[InRegs - 1] - 1;

		break;
	case SDLK_RIGHT:
		InRegs = (InRegs + 1) % (RegsCols + 1);
                if(InRegs && RegsPos >= RegsColsCounts[InRegs - 1])
                  RegsPos = RegsColsCounts[InRegs - 1] - 1;
		break;
        case SDLK_UP:
	  if(InRegs)
	  {
		if(RegsPos)
		 RegsPos--;
	  }
	  else
	  {
           if(event->key.keysym.mod & KMOD_SHIFT)
	   {
	    if(WatchLogical)
             WatchAddr = (WatchAddr - 0x10) & 0xFFFF;
	    else
	     WatchAddrPhys = (WatchAddrPhys - 0x10) & (((uint64)1 << CurGame->Debugger->PhysAddrBits) - 1);
	   }
           else
	   {
            NeedDisAddrChange = -1;
	   }
	  }
          break;
         case SDLK_DOWN:
	  if(InRegs)
	  {
                if(RegsPos < (RegsColsCounts[InRegs - 1] - 1))
		 RegsPos++;
	  }
	  else
	  {
           if(event->key.keysym.mod & KMOD_SHIFT)
	   {
	    if(WatchLogical)
             WatchAddr = (WatchAddr + 0x10) & 0xFFFF;
	    else
	     WatchAddrPhys = (WatchAddrPhys + 0x10) & (((uint64)1 << CurGame->Debugger->PhysAddrBits) - 1);
	   }
           else
	   {
	    NeedDisAddrChange = 1;
	   }
	  }
          break;

         case SDLK_SPACE:
		NeedPCBPToggle = 1;
		break;
	 case SDLK_s:
		LockDebuggerMutex(1);
		NeedStep = 2;
		LockDebuggerMutex(0);
		break;
	 case SDLK_d:
		if(event->key.keysym.mod & KMOD_SHIFT)
		{
		 InPrompt = DumpGfxMem;
		 PromptText = "Dump Gfx Memory(start end filename)";
		}
		else
		{
		 InPrompt = DumpMem;
		 PromptText = "Dump Memory(start end filename)";
		}
		break;
	 case SDLK_w:
                if(event->key.keysym.mod & KMOD_SHIFT)
                {
                 InPrompt = WriteBPS;
                 PromptText = "Write Breakpoints";
                 for(int x = 0; x < WriteBreakpoints.size(); x++)
                 {
                  char short_buf[2];

                  short_buf[0] = WriteBreakpoints[x];
                  short_buf[1] = 0;

                  kb_buffer.push_back(std::string(short_buf));
		  kb_cursor_pos++;
                 }
                }
		break;

	 case SDLK_r:
		if(event->key.keysym.mod & KMOD_SHIFT)
		{
		 InPrompt = ReadBPS;
		 PromptText = "Read Breakpoints";

		 for(int x = 0; x < ReadBreakpoints.size(); x++)
		 {
                  char short_buf[2];

                  short_buf[0] = ReadBreakpoints[x];
                  short_buf[1] = 0;

                  kb_buffer.push_back(std::string(short_buf));
		  kb_cursor_pos++;
		 }	
		}
		else
		 NeedRun = 1;
		break;

	 case SDLK_p:
		if(!InPrompt)
		{
		 if(event->key.keysym.mod & KMOD_SHIFT)
		 {
		  InPrompt = PokeMeHL;
		  PromptText = "HL Poke(address value size)";
		 }
		 else
		 {
		  InPrompt = PokeMe;
		  PromptText = "Poke(address value size)";
		 }
		}
		break;

	  case SDLK_RETURN:
		 {
		  char buf[64];

		  if(event->key.keysym.mod & KMOD_SHIFT)
		  {
		   InPrompt = WatchGoto;
		   PromptText = "Watch Address";
                   snprintf(buf, 64, "%08X", WatchLogical ? WatchAddr : WatchAddrPhys);
	 	  }
		  else
		  {
		   if(InRegs)
		   {
		    InPrompt = (PromptType)(EditRegs0 + InRegs - 1);
		    PromptText = CurGame->Debugger->Regs[InRegs - 1][RegsPos].name;
		    int len = CurGame->Debugger->Regs[InRegs - 1][RegsPos].bsize;

		    uint32 RegValue = CurGame->Debugger->GetRegister(PromptText);

		    if(len == 1)
		     snprintf(buf, 64, "%02X", RegValue);
		    else if(len == 2)
		     snprintf(buf, 64, "%04X", RegValue);
		    else
		     snprintf(buf, 64, "%08X", RegValue);
		   }
		   else
		   {
		    InPrompt = DisGoto;
		    PromptText = "Disassembly Address";
                    snprintf(buf, 64, "%04X", DisAddr);
		   }
		  }

		  for(size_t x = 0; x < strlen(buf); x++)
		  {
		   char short_buf[2];

		   short_buf[0] = buf[x];
		   short_buf[1] = 0;

		   kb_buffer.push_back(std::string(short_buf));
		   kb_cursor_pos++;
		  }

		 }
	         break;
         }
         break;
  }
 return(1);
}

