Emulator progress: build, link, some startup

This commit is contained in:
Lephenixnoir 2021-09-20 10:24:18 +02:00
parent 5f9e27b07a
commit 31daa78aa0
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
17 changed files with 308 additions and 344 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/CGDoom
build-cg/
build-sdl2/
wad/

View File

@ -44,7 +44,8 @@ CG_OBJ := $(SRC:cgdoom/%=build-cg/%.o) $(CG_SRC:src-cg/%=build-cg/%.o)
CC ?= gcc
SDL2_CFLAGS := $(CFLAGS) -I src-sdl2 -DCG_EMULATOR $(pkg-config sdl2 --cflags)
SDL2_LDFLAGS := $(LDFLAGS) $(pkg-config sdl2 --libs)
SDL2_CFLAGS += -O0 -g
SDL2_LDFLAGS := $(LDFLAGS) $(shell pkg-config sdl2 --libs)
SDL2_SRC := $(wildcard src-sdl2/*.c)
SDL2_OBJ := $(SRC:cgdoom/%=build-sdl2/%.o) $(SDL2_SRC:src-sdl2/%=build-sdl2/%.o)

View File

@ -375,7 +375,7 @@ int Layout_Event(Layout *l, int key)
return 0;
}
int UI_Main(WADFileInfo *wads, int wad_count, int *dev_info, int *use_mmap,
int UI_Main(CGD_WADFileInfo *wads, int wad_count, int *dev_info, int *use_mmap,
int *startmap, int *startepisode, int *trustunaligned,
int *autostart, int *enabledemos, int *enable2MBline)
{

View File

@ -61,7 +61,7 @@ int Layout_Event(Layout *l, int key);
/* Larger-scale functions. */
/* Show the program's main screen; returns index of selected WAD file. */
int UI_Main(WADFileInfo *wads, int wad_count,
int UI_Main(CGD_WADFileInfo *wads, int wad_count,
int *dev_info, /* Enable technical detail screens */
int *use_mmap, /* Map file to memory (as opposed to using Bfile) */
int *startmap, /* Warp to this map */

View File

@ -73,24 +73,9 @@ int strnicmp(const char *s1,const char *s2,int count)
// FLASH_END (of which there are 4096) are indexed by their first 4 bytes and
// binary searched for matches before anything else.
//
// See <platform.h> for Flash traversal parameters.
// See <src-cg/platform.h> for Flash traversal parameters.
///////////////////////////////////////////////////////////////////////////////
#ifndef CG_EMULATOR
//The whole sound doesn't fir onto the RAM.
//Reading per partes is not possible as this is synchronnous player (there would be silences when reading).
/* Fast memcmp() for 512-byte sectors. */
int CGD_sector_memcmp(const void *fast_ram, const void *rom, size_t _512);
/* Caching structure to read WAD files by larger chunks than Flash sectors. */
typedef struct {
int fd;
int size, offset;
char *data; /* of size FLASH_BFILE_UNIT */
} FileAccessCache;
/* Index of most likely ROM sectors. */
typedef struct {
const void *sector;
@ -124,30 +109,6 @@ typedef struct {
int miTotalLength;
} FileMapping;
/* Find WAD files in the filesystem. */
int FindWADs(WADFileInfo *files, int max)
{
uint16_t path[32];
Bfile_FileInfo info;
int sd, rc, total=0;
rc = Bfile_FindFirst(u"\\\\fls0\\*.wad", &sd, path, &info);
while(rc != -16 && total < max)
{
memcpy(files[total].path, u"\\\\fls0\\", 14);
memcpy(files[total].path+7, path, 32*2);
Bfile_NameToStr_ncpy(files[total].name, path, 32);
files[total].size = info.fsize;
total++;
rc = Bfile_FindNext(sd, path, &info);
}
Bfile_FindClose(sd);
return total;
}
/* WAD file access method. */
static int gWADmethod = CGDOOM_WAD_MMAP;
/* File descriptor to WAD, used in Flash_ReadFile calls. (CGDOOM_WAD_BFILE) */
@ -173,6 +134,21 @@ struct CGD_Perf CGD_Perf;
/* Developer statistics */
struct CGD_Stats CGD_Stats;
#ifndef CG_EMULATOR
//The whole sound doesn't fir onto the RAM.
//Reading per partes is not possible as this is synchronnous player (there would be silences when reading).
/* Fast memcmp() for 512-byte sectors. */
int CGD_sector_memcmp(const void *fast_ram, const void *rom, size_t _512);
/* Caching structure to read WAD files by larger chunks than Flash sectors. */
typedef struct {
int fd;
int size, offset;
char *data; /* of size FLASH_BFILE_UNIT */
} FileAccessCache;
/* Read next sector from file, while caching into a buffer. */
const void *ReadNextSector(FileAccessCache *fc, int *size)
{
@ -372,6 +348,30 @@ int FindInFlash(const void **buf, int size, int readpos)
return iAvailableLen;
}
static int FindZeroedMemory(void *start)
{
/* Look for zero-longwords every 16 bytes */
int size = 0;
/* Limit to 6 MB since the fx-CG 50 doesn't have any more memory and
anything after the RAM is likely to be zero non-writable */
while(size < CGDOOM_2MBLINEMEMORY_MAX && !*(uint32_t *)(start + size))
size += 16;
/* Round down to a multiple of 4096 */
return size & ~0xfff;
}
void abort(void){
int x=0,y=160;
PrintMini(&x,&y,"Abort called",0,0xFFFFFFFF,0,0,0xFFFF,0,1,0);
int key;
for(;;)
GetKey(&key);
}
#endif /* CG_EMULATOR */
int Flash_ReadFile(void *buf, int size, int readpos)
{
if(gWADmethod == CGDOOM_WAD_BFILE)
@ -396,30 +396,30 @@ int Flash_ReadFile(void *buf, int size, int readpos)
return iRet;
}
static int FindZeroedMemory(void *start)
/* Find WAD files in the filesystem. */
int FindWADs(CGD_WADFileInfo *files, int max)
{
/* Look for zero-longwords every 16 bytes */
int size = 0;
uint16_t path[32];
Bfile_FileInfo info;
/* Limit to 6 MB since the fx-CG 50 doesn't have any more memory and
anything after the RAM is likely to be zero non-writable */
while(size < CGDOOM_2MBLINEMEMORY_MAX && !*(uint32_t *)(start + size))
size += 16;
int sd, rc, total=0;
rc = Bfile_FindFirst(u"\\\\fls0\\*.wad", &sd, path, &info);
/* Round down to a multiple of 4096 */
return size & ~0xfff;
while(rc != -16 && total < max)
{
memcpy(files[total].path, u"\\\\fls0\\", 14);
memcpy(files[total].path+7, path, 32*2);
Bfile_NameToStr_ncpy(files[total].name, path, 32);
files[total].size = info.fsize;
total++;
rc = Bfile_FindNext(sd, path, &info);
}
Bfile_FindClose(sd);
return total;
}
void abort(void){
int x=0,y=160;
PrintMini(&x,&y,"Abort called",0,0xFFFFFFFF,0,0,0xFFFF,0,1,0);
int key;
for(;;)
GetKey(&key);
}
#endif /* CG_EMULATOR */
static void DelayedWriteFile(int i)
{
CGD_DelayedFileWrite const *dfw = &CGD_DelayedSaves[i];
@ -484,14 +484,14 @@ int main(void)
prof_init();
WADFileInfo wads[16];
CGD_WADFileInfo wads[16];
int wad_count = FindWADs(wads, 16);
int dev_info = 0;
/* Allow the user to use memory past the 2 MB line on known OS versions */
int *enable_2MBline=NULL;
char const *osv = (void *)0x80020020;
char const *osv = GetOSVersion();
if(!strncmp(osv, "03.", 3) && osv[3] <= '6') // 3.60 or earlier
enable_2MBline = &CGD_2MBLineMemory;
@ -503,6 +503,13 @@ int main(void)
autostart = autostart_;
/* Parameters unavailable on the SDL2 build */
#ifdef CG_EMULATOR
gWADmethod = CGDOOM_WAD_BFILE;
CGD_TrustUnalignedLumps = 0;
CGD_2MBLineMemory = 0;
#endif
/* Override version detection for single-episode Ultimate Doom WADs */
if (!strcmp(wads[choice].name, "doomu1.wad"))
CGD_SingleEpisodeUltimate = 1;
@ -513,8 +520,9 @@ int main(void)
if (!strcmp(wads[choice].name, "doomu4.wad"))
CGD_SingleEpisodeUltimate = 4;
unsigned tmp=((unsigned)getSecondaryVramAddress()+3)&(~3);
SaveVRAMBuffer = (unsigned char*)tmp;
uintptr_t secondary_vram = ((uintptr_t)GetSecondaryVRAMAddress() | 3) + 1;
SaveVRAMBuffer = (void *)secondary_vram;
/* fx-CG 50 / Graph 90+E: RAM starts at 0x0c000000 in physical memory */
SystemStack = (void *)0xac0f0000;
@ -529,9 +537,6 @@ int main(void)
CGD_WADFileName = wad_name;
/* Setup access to WAD file */
#ifdef CG_EMULATOR
gWADmethod = CGDOOM_WAD_BFILE;
#endif
if(gWADmethod == CGDOOM_WAD_BFILE)
{
gWADfd = Bfile_OpenFile_OS(wads[choice].path, 0, 0);

View File

@ -1,6 +1,7 @@
#ifndef CGDOOM_H
#define CGDOOM_H
#include "platform.h"
#include "libprof.h"
#include <stdint.h>
@ -17,7 +18,7 @@ typedef struct
char name[32];
uint16_t path[7+32];
int size;
} WADFileInfo;
} CGD_WADFileInfo;
/* Description of a file write that has been delated. */
typedef struct
@ -53,6 +54,10 @@ extern int CGD_EnableDemos;
extern int CGD_SingleEpisodeUltimate;
/* Skip this amount of frames after every rendered frame (default 1) */
extern int CGD_Frameskip;
/* Whether to trust unaligned lumps. If this is set, all non-fragmented lumps
will be accessed from ROM. Otherwise, lumps that are not 4-aligned will be
loaded to the heap even if they are available. (CGDOOM_WAD_MMAP) */
extern int CGD_TrustUnalignedLumps;
// Global variables interfacing with Doom itself.

View File

@ -28,6 +28,8 @@
#ifndef __BYTEBOOL__
#define __BYTEBOOL__
#include <stdint.h>
// Fixed to use builtin bool type with C++.
/*#ifdef __cplusplus
typedef bool boolean;

View File

@ -143,7 +143,7 @@ int wipe_initMelt( int width, int height, int ticks )
/* See wipe_doMelt(). */
short SPU2_read16(short *x)
{
if ((int)x & 2) {
if ((uintptr_t)x & 2) {
volatile int *z = (int *)(x - 1);
return *z & 0xffff;
}

View File

@ -20,6 +20,6 @@ int strnicmp (const char*s1,const char*s2,int iLen);
void I_Error (const char *error, ...);
//return ptr to flash
int FindInFlash(const void **buf, int size, int readpos);
int (FindInFlash)(const void **buf, int size, int readpos);
//direct read from flash
int Flash_ReadFile(void *buf, int size, int readpos);

View File

@ -36,7 +36,7 @@ byte* save_p;
// Pads save_p to a 4-byte boundary
// so that the load/save works on SGI&Gecko.
#define PADSAVEP() save_p += (4 - ((int) save_p & 3)) & 3
#define PADSAVEP() save_p += (4 - ((uintptr_t) save_p & 3)) & 3

View File

@ -299,7 +299,7 @@ void * W_ReadLumpWithZ_Malloc(int lump,int tag,int iEnableFlash)
}
int full = (c == lumpinfo[lump].size);
int aligned = (((uint32_t)lumpcache[lump] & 1) == 0);
int aligned = (((uintptr_t)lumpcache[lump] & 1) == 0);
if(CGD_TrustUnalignedLumps)
aligned = 1;

View File

@ -472,7 +472,7 @@ void Z_ChangeTag2(const void* ptr,int tag )
I_Error ("Z_ChangeTag: freed a pointer without ZONEID: %p", ptr);
}
if (tag >= PU_PURGELEVEL && (unsigned)block->user < 0x100)
if (tag >= PU_PURGELEVEL && (uintptr_t)block->user < 0x100)
{
I_Error ("Z_ChangeTag: an owner is required for purgable blocks");
}

View File

@ -41,11 +41,6 @@
almost always 4 kiB-aligned, and only occasionally not */
#define FLASH_INDEX_SIZE ((FLASH_END-FLASH_FS_HINT) / 4096)
/* Whether to trust unaligned lumps. If this is set, all non-fragmented lumps
will be accessed from ROM. Otherwise, lumps that are not 4-aligned will be
loaded to the heap even if they are available. */
extern int CGD_TrustUnalignedLumps;
//---
// Display driver access
//---
@ -96,5 +91,6 @@ extern int CGD_2MBLineMemory;
#include <stdint.h>
#define ASSERT(x)
#define GetOSVersion() ((char *)0x80020020)
#endif //#ifndef PLATFORM_H

View File

@ -1,7 +1,9 @@
#include "cgdoom.h"
#include "platform.h"
#include "i_system.h"
#include <SDL2/SDL.h>
#include <stdio.h>
#include <glob.h>
SDL_Window *window = NULL;
SDL_Surface *VRAM_RGB888 = NULL;
@ -9,6 +11,7 @@ SDL_Surface *VRAM_RGB888 = NULL;
/* Rendering system emulation. */
uint16_t _VRAM[WIDTH * HEIGHT];
uint16_t _VRAM2[WIDTH * HEIGHT];
static void QuitSDL(void)
{
@ -46,6 +49,11 @@ uint16_t *GetVRAMAddress(void)
return _VRAM;
}
uint16_t *GetSecondaryVRAMAddress(void)
{
return _VRAM2;
}
void Bdisp_PutDisp_DD(void)
{
if(!window)
@ -87,6 +95,14 @@ void Bdisp_AllClr_VRAM(void)
/* Keyboard system emulation. */
int PRGM_GetKey(void)
{
// TODO: PRGM_GetKey()
// We don't really need it here, it's only used to delay error messages
// on-calc, and these are printed on terminal
return 0;
}
void GetKey(int *key)
{
SDL_Event e;
@ -113,27 +129,14 @@ void GetKey(int *key)
}
}
/* Main function */
int main(int argc,char *argv[])
/* Returns the value of a 128 Hz counter */
int RTC_GetTicks(void)
{
}
//Returns the RTC-basecount in units of 1/128 s.
int RTC_GetTicks( void )
{
return GetTickCount()>> 3;//1000/128 is very near to 1000/125
}
//start_value has to be set with RTC_GetTicks.
//duration_in_ms is the duration, which has to elapse since start_value.
//returns 0 if duration_in_ms has not elapsed yet
//returns 1 if duration_in_ms has elapsed
int RTC_Elapsed_ms( int start_value, int duration_in_ms )
{
return (GetTickCount() - duration_in_ms) > (start_value << 3);
struct timespec tp;
clock_gettime(CLOCK_MONOTONIC, &tp);
int msec = (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000);
return (msec * 128) / 1000;
}
void assert(int iLine,const char *pszFilename,const char *pszAassert)
@ -146,42 +149,190 @@ void assert(int iLine,const char *pszFilename,const char *pszAassert)
}
}
//files
//int hFile = Bfile_OpenFile_OS(pFileName,0);
int Bfile_OpenFile_OS( const unsigned short*filename, int mode )
//---
// Filesystem API emulation
//---
#define FILE_TABLE_MAX 16
static FILE *file_table[FILE_TABLE_MAX] = { NULL };
static struct {
int pos;
glob_t glob;
} search_table[FILE_TABLE_MAX];
void Bfile_NameToStr_ncpy(char *dest, const uint16_t *source, size_t n)
{
FILE *f;
char szFileName[1024];
int i = 0;
filename += 7;//\\fls0\
while(filename[0])
{
szFileName[i] = (char)filename[0];
filename++;i++;
size_t i = 0;
while(i < n && source[i] != 0x0000 && source[i] != 0xffff) {
dest[i] = source[i];
i++;
}
szFileName[i] = 0;
f = fopen(szFileName,"rb");
return f?(int)f:-1;
for(size_t j = i; j < n; j++)
dest[j] = source[i];
}
int Bfile_SeekFile_OS( int HANDLE, int pos )
void Bfile_StrToName_ncpy(uint16_t *dest, const char *source, size_t n)
{
fseek((FILE*)HANDLE,pos,SEEK_SET);
size_t i = 0;
while(i < n && source[i]) {
dest[i] = source[i];
i++;
}
while(i < n)
dest[i++] = 0;
}
int Bfile_DeleteEntry(const uint16_t *filename_u16)
{
char filename_u8[1024];
Bfile_NameToStr_ncpy(filename_u8, filename_u16, 1024);
printf("Deleting %s (virtually)", filename_u8);
return 0;
}
int Bfile_ReadFile_OS( int HANDLE, void *buf, int size, int readpos )
int Bfile_CreateEntry_OS(const uint16_t *filename_u16, int mode, size_t *size)
{
char filename_u8[1024];
Bfile_NameToStr_ncpy(filename_u8, filename_u16, 1024);
if(mode == BFILE_CREATEMODE_FILE) {
printf("Creating %s with size %zu (virtually)", filename_u8, *size);
}
else if(mode == BFILE_CREATEMODE_FOLDER) {
I_Error("Cannot create folder %s: Not Implemented", filename_u8);
return -1;
}
else {
I_Error("Bfile_CreateEntry_OS(): Invalid mode %d", mode);
return -1;
}
return 0;
}
int Bfile_OpenFile_OS(const uint16_t *filename_u16, int mode, int zero)
{
(void)zero;
char filename_u8[1024];
Bfile_NameToStr_ncpy(filename_u8, filename_u16, 1024);
char const *bits;
if(mode == BFILE_READ || mode == BFILE_READ_SHARE)
bits = "rb";
else if(mode == BFILE_WRITE)
bits = "wb";
else if(mode == BFILE_READWRITE || mode == BFILE_READWRITE_SHARE)
bits = "w+b";
else {
I_Error("Bfile_OpenFile_OS(): invalid mode %d for %s", mode, filename_u8);
return -1;
}
FILE *fp = fopen(filename_u8, bits);
if(!fp) {
I_Error("Bfile_OpenFile_OS(): cannot open %s: %m", filename_u8);
return -1;
}
/* Find open slot in file table */
int slot = 0;
while(slot < FILE_TABLE_MAX && file_table[slot] != NULL)
slot++;
if(slot >= FILE_TABLE_MAX) {
I_Error("Bfile_OpenFile_OS(): cannot open %s, table is full", filename_u8);
fclose(fp);
return -1;
}
file_table[slot] = fp;
return slot;
}
int Bfile_GetFileSize_OS(int fd)
{
FILE *fp = file_table[fd];
long pos = ftell(fp);
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
fseek(fp, pos, SEEK_SET);
return size;
}
int Bfile_SeekFile_OS(int fd, int pos)
{
fseek(file_table[fd], pos, SEEK_SET);
return 0;
}
int Bfile_ReadFile_OS(int fd, void *buf, int size, int readpos)
{
if(readpos != -1)
{
Bfile_SeekFile_OS(HANDLE, readpos );
}
//fread ( dest, size elements, count elements, FILE handle );
return fread(buf,1,size,(FILE*)HANDLE);
Bfile_SeekFile_OS(fd, readpos);
return fread(buf, 1, size, file_table[fd]);
}
int Bfile_CloseFile_OS( int HANDLE )
int Bfile_WriteFile_OS(int fd, const void *buf, int size)
{
fclose((FILE*)HANDLE);
return fwrite(buf, 1, size, file_table[fd]);
}
int Bfile_CloseFile_OS(int fd)
{
fclose(file_table[fd]);
file_table[fd] = NULL;
return 0;
}
int Bfile_FindFirst(const uint16_t *pattern_u16, int *fd, uint16_t *found,
void *fileinfo)
{
char pattern_u8[1024];
Bfile_NameToStr_ncpy(pattern_u8, pattern_u16, 1024);
int slot = 0;
while(slot < FILE_TABLE_MAX && search_table[slot].pos != 0)
slot++;
if(slot >= FILE_TABLE_MAX) {
I_Error("Bfile_FindFirst(): cannot search %s, table is full", pattern_u8);
*fd = -1;
return -16;
}
int rc = glob(pattern_u8, 0, NULL, &search_table[slot].glob);
if(rc == GLOB_NOMATCH)
return -16;
*fd = slot;
return Bfile_FindNext(slot, found, fileinfo);
}
int Bfile_FindNext(int fd, uint16_t *found, void *fileinfo0)
{
int *pos = &search_table[fd].pos;
glob_t *glob = &search_table[fd].glob;
if(*pos >= glob->gl_pathc)
return -16;
const char *name = glob->gl_pathv[*pos];
Bfile_StrToName_ncpy(found, name, strlen(name));
(*pos)++;
Bfile_FileInfo *fileinfo = fileinfo0;
fileinfo->fsize = 0;
return 0;
}
int Bfile_FindClose(int fd)
{
if(fd < 0 || fd >= FILE_TABLE_MAX)
return -1;
search_table[fd].pos = 0;
globfree(&search_table[fd].glob);
return 0;
}

View File

@ -3,57 +3,54 @@
#define PLATFORM_H
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "keyboard.hpp"
#include "../../../include/fxcg/file.h"
//---
// fx-CG-specific functions not defined on emulator
//---
#define CreateFileMapping(...) 0
#define FindInFlash(...) 0
#define FindZeroedMemory(...) 0
/* On the emulator all lumps are allocated with malloc(), so there are not
pointers-to-flash to account for when freeing. */
#define PTR_TO_FLASH(p) 0
/* Rendering system emulation. */
//---
// Rendering system emulation
//---
void Bdisp_PutDisp_DD(void);
void Bdisp_AllClr_VRAM(void);
uint16_t *GetVRAMAddress(void);
uint16_t *GetSecondaryVRAMAddress(void);
int Bdisp_FrameAndColor(int, int);
#define EnableColor(...)
#define EnableStatusArea(...)
/* Input system emulation. */
//---
// Filesystem API emulation
//---
#include "../../../include/fxcg/file.h"
//---
// Other functions
//---
int PRGM_GetKey(void);
void GetKey(int *key);
//~
void G3A_main( void );
int Serial_Open( unsigned char *mode );
int Serial_Close( int mode );
int Serial_DirectTransmitOneByte( unsigned char byte_to_transmit );
int Serial_CheckRX();
unsigned char Serial_Read();
#define dbgprint(x) printf(x)
#define dbgprint1(x,y) printf(x,y)
int RTC_GetTicks( void );
int RTC_Elapsed_ms( int start_value, int duration_in_ms );
void Sleep(int dwMilliseconds );
#define EmulHack_Sleep(x) Sleep(x)
int RTC_GetTicks(void);
void assert(int iLine,const char *pszFilename,const char *pszAassert);
#define ASSERT(x) if(!(x)){assert(__LINE__,__FILE__,#x);}
extern const unsigned char *gpcFlashBuffer;
void InitFlashSimu(const char *filename);
#define GetOSVersion() ("03.60.0000")
#endif /* PLATFORM_H */

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

View File

@ -1,194 +0,0 @@
#include <windows.h>
#include <windowsx.h>
#include "keyboard.hpp"
HBITMAP ghbm;
BOOL OnCreate(HWND hwnd)
{
ghbm = (HBITMAP) LoadImage (0, "./tastatur.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
return TRUE;
}
BOOL OnDestroy(HWND hwnd)
{
DeleteObject(ghbm);
PostQuitMessage(0);
return TRUE;
}
BOOL OnPaint(HWND hwnd)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd,&ps);
HDC hdcMem = CreateCompatibleDC(NULL);
HBITMAP hbmT = SelectBitmap(hdcMem,ghbm);
BITMAP bm;
GetObject(ghbm,sizeof(bm),&bm);
BitBlt(hdc,0,0,bm.bmWidth,bm.bmHeight,hdcMem,0,0,SRCCOPY);
SelectBitmap(hdcMem,hbmT);
DeleteDC(hdcMem);
EndPaint(hwnd,&ps);
return TRUE;
}
void HandleButton(int x,int y);
void HandleButtonDown(int x,int y);
void HandleButtonUp();
LRESULT CALLBACK KeyboardWindowProc( HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
static int x,y;
switch(uMsg)
{
case WM_CREATE:return OnCreate(hwnd);
case WM_DESTROY:return OnDestroy(hwnd);
case WM_PAINT:return OnPaint(hwnd);
case WM_MOUSEMOVE:x = LOWORD(lParam);y = HIWORD(lParam);return TRUE;
case WM_LBUTTONDOWN:HandleButtonDown(x,y);return TRUE;
case WM_LBUTTONUP:HandleButtonUp();return TRUE;
case WM_SIZE:return TRUE;
default:return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
}
void KeyboardRegisterClass()
{
WNDCLASS wc = {0,KeyboardWindowProc,0,0, NULL,
LoadIcon(NULL,IDI_APPLICATION),
LoadCursor(NULL,IDC_ARROW),
(HBRUSH)(COLOR_WINDOW+1),
NULL,
"Keyboard" };
RegisterClass(&wc);
}
DWORD __stdcall KeyboardFunc(void *p)
{
HWND hwnd;
MSG msg;
KeyboardRegisterClass();
hwnd = CreateWindowA("Keyboard","Keyboard",WS_OVERLAPPED,500,0,CW_USEDEFAULT,0,HWND_DESKTOP,NULL,NULL,NULL);
ShowWindow(hwnd,SW_SHOW);
SetWindowPos(hwnd,HWND_TOP,0,0,260+8,362+23+4 ,SWP_NOMOVE);
UpdateWindow(hwnd);
while(GetMessage(&msg,0,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
////////////////////////////////////////////////////////////////////////////////////////////////
#define L_OFFSET 3
#define ROWS1_WIDTH 36
#define ROWS1_GRID 43
#define ROWS1_COUNT 5
#define ROWS1_HEIGHT 22
//const int giRows1[ROWS1_COUNT]={8,47,84,121,158};
#define ROWS2_WIDTH 44
#define ROWS2_GRID 52
#define ROWS2_COUNT 4
#define ROWS2_HEIGHT 22
//const int giRows2[ROWS2_COUNT]={199,243,287,331};
#define ROWS_COUNT (ROWS1_COUNT+ROWS2_COUNT)
#define ROWS_HEIGHT 22
const int giRows[ROWS1_COUNT+ROWS2_COUNT]={8,47,84,121,158,199,243,287,331};
//extra arrows
const int giUp[2]={218,50};
const int giDown[2]={218,93};
const int giLeft[2]={189,70};
const int giRight[2]={245,70};
#define ARROW_HWIDTH (ROWS1_HEIGHT >>1)
#define ARROW_HHEIGHT (ROWS_HEIGHT >>1)
static int IsArrow(const int *pi,int x,int y)
{
if(x<(pi[0]-ARROW_HWIDTH))return 0;
if(x>(pi[0]+ARROW_HWIDTH))return 0;
if(y<(pi[1]-ARROW_HHEIGHT))return 0;
if(y>(pi[1]+ARROW_HHEIGHT))return 0;
return 1;
}
int FindButton(int x,int y)
{
int i,iRow=-1,iCol;
if(IsArrow(giUp ,x,y))return KEY_PRGM_UP;
if(IsArrow(giDown ,x,y))return KEY_PRGM_DOWN;
if(IsArrow(giLeft ,x,y))return KEY_PRGM_LEFT;
if(IsArrow(giRight,x,y))return KEY_PRGM_RIGHT;
x -= L_OFFSET;
if(x< 0) return KEY_PRGM_NONE;
for(i=0;i<ROWS_COUNT;i++)
{
if((y >= giRows[i]) && (y <= giRows[i]+ ROWS_HEIGHT))
{
iRow = i;
break;
}
}
if(iRow == -1)return KEY_PRGM_NONE;
if(iRow < ROWS1_COUNT)
{
if((x % ROWS1_GRID) > ROWS1_WIDTH)return KEY_PRGM_NONE;
iCol = x / ROWS1_GRID;
}
else
{
if((x % ROWS2_GRID) > ROWS2_WIDTH)return KEY_PRGM_NONE;
iCol = x / ROWS2_GRID;
}
iRow = 9-iRow;
iCol = 7 - iCol;
i = iRow + 10*iCol;
switch(i)
{
case KEY_PRGM_LEFT:
case KEY_PRGM_RIGHT:
case KEY_PRGM_UP:
case KEY_PRGM_DOWN:
return KEY_PRGM_NONE;
case 34:
i = KEY_PRGM_ACON;
}
return i;
}
KeyHandler(int iKey);
void HandleButton(int x,int y)
{
int iKey = FindButton(x,y);
if(iKey)
{
KeyHandler(iKey);
}
}
int iKeyDown = 0;
void HandleButtonDown(int x,int y)
{
iKeyDown = FindButton(x,y);
}
void HandleButtonUp()
{
iKeyDown = 0;
}