Sign in to follow this  
Vincent Torri

Ipaq 3970 and GAPI: strangeness with keys

Recommended Posts

Hey, I'm still trying to make GAPI working nicely with my program. Now I have a problem with keys. I get the keys with GXGetDefaultKeys(GX_NORMALKEYS). In the window procedure, I display the value of wParam and the values of the keys returned by GXGetDefaultKeys(). The left/right/up/bottom are correct. But the other keys are not. values returned by GXGetDefaultKeys() for vk(A, B, C, Start) : 195, 196, 197, 134 value of wParam: 193, 194, 195, 196 for the for keys. Does someone know if the Ipaq 3970 has some problems with GAPI, with respect to the keys ? (I know that it is buggy wrt to the screen and the pitch, but it's something that I have already managed)

Share this post


Link to post
Share on other sites
As a reminder from the last thread, GAPI IS DEPRICATED, and it is known to fail on many devices released after 2005 or so, as well as some devices released before then. It fails or has problems on many VGA devices, and can result in slower performance than regular GDI on any non-QVGA device.

Don't use it unless you have strong reasons compelling you to.


The normal methods for input handling include using the regular WM_KEYDOWN and similar messages in your message handling, or the GetKeyState() and GetAsyncKeyState() functions. Read their documentation, since they are slightly different than the PC functions with the same name.

Share this post


Link to post
Share on other sites
1) I know that it is deprecated. I didn't loose my memory since the previous thread.

2) ipaq H3970 was released in 2002

3) To do some graphics with a good speed, i can't use gdi. So I have the choice between raw framebuffer, gapi and directdraw. Raw framebuffer is not supported, and no directdraw for that device. Hence, yes, I have a good reason to use gapi with that device. If you have another option to get *fast* drawing with wince, I would be pleased to know.

btw, here is the full code

// arm-wince-cegcc-gcc -g -Wall -o winmo2.exe winmo2.c -laygshell -Wl,--enable-auto-import

#include <stdio.h>

#include <windows.h>
#include <aygshell.h>

#ifdef __ARM4__
# warning "arm 4 present"
#else
# warning "arm 4 non present"
#endif

#ifdef __ARM5__
# warning "arm 5 present"
#else
# warning "arm 5 non present"
#endif

typedef enum
{
BACKEND_RAWFRAMEBUFFER,
BACKEND_GAPI
} Backend;


// Raw buffer

#define GETRAWFRAMEBUFFER 0x00020001
#define FORMAT_565 1

typedef struct _RawFrameBufferInfo
{
WORD wFormat;
WORD wBPP;
VOID *pFramePointer;
int cxStride;
int cyStride;
int cxPixels;
int cyPixels;
} RawFrameBufferInfo;


// GAPI

#define LINK(type,name,import) name = (fct_##type)GetProcAddress (GX_lib, import)

#define GX_FULLSCREEN 0x01
#define GX_NORMALKEYS 0x02

#define kfDirect555 0x40
#define kfDirect565 0x80

typedef struct _GXDisplayProperties
{
DWORD cxWidth;
DWORD cyHeight;
LONG cbxPitch;
LONG cbyPitch;
LONG cBPP;
DWORD ffFormat;
} GXDisplayProperties;

typedef struct _GXKeyList {
short vkUp; // key for up
POINT ptUp; // x,y position of key/button. Not on screen but in screen coordinates.
short vkDown;
POINT ptDown;
short vkLeft;
POINT ptLeft;
short vkRight;
POINT ptRight;
short vkA;
POINT ptA;
short vkB;
POINT ptB;
short vkC;
POINT ptC;
short vkStart;
POINT ptStart;
} GXKeyList;

typedef int (*fct_GXOpenDisplay)(HWND hWnd, DWORD dwFlags);
typedef int (*fct_GXCloseDisplay)();
typedef GXDisplayProperties (*fct_GXGetDisplayProperties)();
typedef void* (*fct_GXBeginDraw)();
typedef int (*fct_GXEndDraw)();
typedef int (*fct_GXOpenInput)();
typedef int (*fct_GXCloseInput)();
typedef GXKeyList (*fct_GXGetDefaultKeys)(int iOptions);
typedef int (*fct_GXSuspend)();
typedef int (*fct_GXResume)();

HMODULE GX_lib = NULL;

fct_GXOpenDisplay GXOpenDisplay = NULL;
fct_GXCloseDisplay GXCloseDisplay = NULL;
fct_GXGetDisplayProperties GXGetDisplayProperties = NULL;
fct_GXBeginDraw GXBeginDraw = NULL;
fct_GXEndDraw GXEndDraw = NULL;
fct_GXOpenInput GXOpenInput = NULL;
fct_GXCloseInput GXCloseInput = NULL;
fct_GXGetDefaultKeys GXGetDefaultKeys = NULL;
fct_GXSuspend GXSuspend = NULL;
fct_GXResume GXResume = NULL;

GXKeyList gx_keylist;


// global

HWND window;

int fb_width = 0;
int fb_height = 0;
int fb_stride_x = 0;
int fb_stride_y = 0;
int fb_stride = 0;
int fb_bpp = 0;
void *fb_data = NULL;


static int result = 1;


static LRESULT CALLBACK
window_procedure(HWND window,
UINT msg,
WPARAM wparam,
LPARAM lparam)
{
switch (msg) {
case WM_SYSKEYDOWN:
printf ("key sys down: %d\n", wparam);
break;
case WM_KEYDOWN:
{

printf ("keys : %d %d %d %d\n",
gx_keylist.vkA, gx_keylist.vkB, gx_keylist.vkC, gx_keylist.vkStart);
printf ("key down: %d\n", wparam);
if (wparam == (short)gx_keylist.vkDown) {
printf ("down\n");
printf ("sortie\n");
result = 0;
break;
}
if (wparam == (short)gx_keylist.vkUp) {
printf ("up\n");
break;
}
if (wparam == (short)gx_keylist.vkLeft) {
printf ("left\n");
break;
}
if (wparam == (short)gx_keylist.vkRight) {
printf ("right\n");
break;
}
if (wparam == (short)gx_keylist.vkA) {
fprintf (stderr, "A\n");
printf ("A\n");
break;
}
if (wparam == (short)gx_keylist.vkB) {
printf ("B\n");
break;
}
if (wparam == (short)gx_keylist.vkC) {
printf ("C\n");
break;
}
if (wparam == (short)gx_keylist.vkStart) {
printf ("Start\n");
break;
}
}
case WM_SYSKEYUP:
printf ("key sys up: %d\n", wparam);
break;
case WM_KEYUP:
{
printf ("key up: %d\n", wparam);
if (wparam == (short)gx_keylist.vkDown) {
printf ("down\n");
printf ("sortie\n");
result = 0;
break;
}
if (wparam == (short)gx_keylist.vkUp) {
printf ("up\n");
break;
}
if (wparam == (short)gx_keylist.vkLeft) {
printf ("left\n");
break;
}
if (wparam == (short)gx_keylist.vkRight) {
printf ("right\n");
break;
}
if (wparam == (short)gx_keylist.vkA) {
printf ("A\n");
break;
}
if (wparam == (short)gx_keylist.vkB) {
printf ("B\n");
break;
}
if (wparam == (short)gx_keylist.vkC) {
printf ("C\n");
break;
}
if (wparam == (short)gx_keylist.vkStart) {
printf ("Start\n");
break;
}
}
case WM_DESTROY:
result = 0;
break;
case WM_KILLFOCUS:
if (GXSuspend)
GXSuspend ();
break;
case WM_SETFOCUS:
if (GXResume)
GXResume ();
break;
default:
return DefWindowProc(window, msg, wparam, lparam);
}

return DefWindowProc(window, msg, wparam, lparam);
}

int
window_create ()
{
WNDCLASS wc;
RECT rect;

memset (&wc, 0, sizeof (wc));
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = window_procedure;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle(NULL);
wc.hIcon = NULL;
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
wc.lpszMenuName = NULL;
wc.lpszClassName = L"class name";

RegisterClass(&wc);

//resize window to cover screen
SetRect(&rect, 0, 0,
GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN));

window = CreateWindowEx (WS_EX_TOPMOST,
L"class name", L"",
WS_VISIBLE | WS_POPUP,
rect.left, rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
NULL,
NULL,
GetModuleHandle(NULL),
NULL);
if (!window) {
printf ("error : CreateWindowEx\n");
return 0;
}

// hide task bar, start icon and sip button
SHFullScreen(window,
SHFS_HIDETASKBAR | SHFS_HIDESTARTICON | SHFS_HIDESIPBUTTON);

return 1;
}

void
window_destroy ()
{
if (window)
DestroyWindow (window);
}

int
rawframebuffer_init (void)
{
RawFrameBufferInfo rfbi;
HDC dc;

dc = GetDC (window);

if (!dc)
return 0;

if (!ExtEscape(dc, GETRAWFRAMEBUFFER, 0, 0, sizeof(rfbi), (char *) &rfbi) ||
(rfbi.wFormat != FORMAT_565)) {
ReleaseDC(window, dc);

return 0;
}

fb_width = rfbi.cxPixels;
fb_height = rfbi.cyPixels;
fb_stride_x = rfbi.cxStride;
fb_stride_y = rfbi.cyStride;
fb_bpp = rfbi.wBPP;
fb_data = rfbi.pFramePointer;

ReleaseDC(window, dc);

return 1;
}

void
rawframebuffer_shutdown (void)
{
}

int
rawframebuffer_rect_draw (int x, int y, int w, int h)
{
unsigned short *buffer;
unsigned short *tmp;
int i;
int j;

buffer = (unsigned short *)fb_data;
if (!buffer) {
printf ("error : no raw buffer\n");
return 0;
}

memset (buffer, 0, fb_stride_y * fb_height);

tmp = buffer + y * (fb_stride_y / 2) + x;
for (j = 0; j < h; ++j, tmp += (fb_stride_y / 2)) {
for (i = 0; i < w; i++) {
tmp[i] = (31 << 11) + (0 << 5) + (0 << 0);
}
}

return 1;
}

int
gapi_init (void)
{
GXDisplayProperties prop;

GX_lib = LoadLibrary(L"\\Windows\\gx.dll");
if (!GX_lib) {
GX_lib = LoadLibrary(L"gx.dll");
if (!GX_lib) {
printf ("error : LoadLibrary\n");
return 0;
}
}

LINK(GXOpenDisplay, GXOpenDisplay, L"?GXOpenDisplay@@YAHPAUHWND__@@K@Z");
LINK(GXCloseDisplay, GXCloseDisplay, L"?GXCloseDisplay@@YAHXZ");
LINK(GXGetDisplayProperties, GXGetDisplayProperties, L"?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ");
LINK(GXBeginDraw, GXBeginDraw, L"?GXBeginDraw@@YAPAXXZ");
LINK(GXEndDraw, GXEndDraw, L"?GXEndDraw@@YAHXZ");
LINK(GXOpenInput, GXOpenInput, L"?GXOpenInput@@YAHXZ" );
LINK(GXCloseInput, GXCloseInput, L"?GXCloseInput@@YAHXZ" );
LINK(GXGetDefaultKeys, GXGetDefaultKeys, L"?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z");
LINK(GXSuspend, GXSuspend, L"?GXSuspend@@YAHXZ" );
LINK(GXResume, GXResume, L"?GXResume@@YAHXZ" );

if (!GXOpenDisplay ||
!GXCloseDisplay ||
!GXGetDisplayProperties ||
!GXBeginDraw ||
!GXEndDraw ||
!GXOpenInput ||
!GXCloseInput ||
!GXGetDefaultKeys ||
!GXSuspend ||
!GXResume) {
printf ("error : no valid symbols\n");
FreeLibrary (GX_lib);
return 0;
}

if (!GXOpenDisplay (window, GX_FULLSCREEN)) {
printf ("error : GXOpenDisplay\n");
FreeLibrary (GX_lib);
return 0;
}

prop = GXGetDisplayProperties();

// verify pixel format
if(!(prop.ffFormat & kfDirect565)) {
printf ("error : GAPI format mismatch\n");
GXCloseDisplay ();
FreeLibrary (GX_lib);
return 0;
}

// verify we have a vga device
if ((GetSystemMetrics(SM_CXSCREEN) != (int)prop.cxWidth) ||
(GetSystemMetrics(SM_CYSCREEN) != (int)prop.cyHeight)) {
printf ("error : GAPI format mismatch\n");
GXCloseDisplay ();
FreeLibrary (GX_lib);
return 0;
}

if (!GXOpenInput ()) {
printf ("error : GXOpenInput\n");
GXCloseDisplay ();
FreeLibrary (GX_lib);
return 0;
}

fb_width = prop.cxWidth;
fb_height = prop.cyHeight;
fb_stride_x = prop.cbxPitch;
fb_stride_y = prop.cbyPitch;
fb_bpp = prop.cBPP;

printf ("size1 : %dx%d\n", GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
printf ("size2 : %dx%d\n", fb_width, fb_height);
printf ("stride : %dx%d\n", fb_stride_x, fb_stride_y);
printf ("format : %d %d (%ld)\n", kfDirect555, kfDirect565, prop.ffFormat);
printf ("bpp : %d\n", fb_bpp);

{
WCHAR oemstr[100];

SystemParametersInfo (SPI_GETOEMINFO, sizeof (oemstr), oemstr, 0);
printf ("param: %c %c %c %c\n", oemstr[12], oemstr[13], oemstr[14], oemstr[15]);
/* ipaq h38** and H39** are buggy */
if (((oemstr[12] == 'H') &&
(oemstr[13] == '3') &&
(oemstr[14] == '8')) ||
((oemstr[12] == 'H') &&
(oemstr[13] == '3') &&
(oemstr[14] == '9'))) {
fb_stride = fb_stride_x;
}
else {
fb_stride = fb_stride_y;
}
}
printf ("stride : %d\n", fb_stride);

gx_keylist = GXGetDefaultKeys (GX_NORMALKEYS);

return 1;
}

void
gapi_shutdown (void)
{
GXCloseInput();
GXCloseDisplay ();
FreeLibrary (GX_lib);
GX_lib = NULL;
GXSuspend = NULL;
GXResume = NULL;
}

int
gapi_rect_draw (int x, int y, int w, int h)
{
static unsigned short *back = NULL;
unsigned short *buffer;
unsigned short *tmp;
int j;

/* back buffer */

if (!back) {
back = calloc (fb_width * fb_height, sizeof (unsigned short));
if (!back)
return 0;
}

tmp = back + y + x * (fb_stride / 2);
for (j = 0; j < h; ++j) {
int i;
for (i = 0; i < w; i++) {
int c = ((i + j) * 31) / 60;
tmp[i] = c << 11;
}
/* memset (tmp, 31, 2 * w); */
tmp += (fb_stride / 2);
}

/* we copy to the frame buffer */

buffer = (unsigned short *)GXBeginDraw ();
if (!buffer) {
printf ("error : GXBeginDraw\n");
return 0;
}

memcpy (buffer, back, fb_width * fb_height * 2);

GXEndDraw();

return 1;
}

int
backend_init (Backend backend)
{
switch (backend) {
case BACKEND_RAWFRAMEBUFFER:
return rawframebuffer_init ();
case BACKEND_GAPI:
return gapi_init ();
default:
return 0;
}
}

void
backend_shutdown (Backend backend)
{
switch (backend) {
case BACKEND_RAWFRAMEBUFFER:
rawframebuffer_shutdown ();
break;
case BACKEND_GAPI:
gapi_shutdown ();
break;
default:
break;
}
}

int
rect_draw (Backend backend, int x, int y, int w, int h)
{
switch (backend) {
case BACKEND_RAWFRAMEBUFFER:
return rawframebuffer_rect_draw (x, y, w, h);
case BACKEND_GAPI:
return gapi_rect_draw (x, y, w, h);
default:
return 0;
}
}

int main ()
{
Backend backend;

if (!window_create ()) {
return -1;
}

backend = BACKEND_GAPI;

if (!backend_init (backend)) {
printf ("error backend_init\n");
window_destroy ();
return -1;
}

ShowWindow(window, SW_SHOWNORMAL);
UpdateWindow(window);

while (result) {
MSG msg;

if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage (&msg);
DispatchMessage (&msg);
}
rect_draw (backend, 50, 50, 30, 30);
}

backend_shutdown (backend);
window_destroy ();

return 0;
}

Share this post


Link to post
Share on other sites
You can get perfectly fast access to a virtual frame-buffer through GDI. This will give you essentially the same thing as GAPI, except that you won't be dependent upon the deprecated library. This is how my software graphics library works.

I don't have all the details off the top of my head, but my system works roughly like so:

I have a "Canvas" class which can receive drawing operations or supply imagery for drawing operations. At this point, the frame-buffer provided by canvas is just system memory in a color format supported by GDI (and preferably the device, to avoid a bit-depth conversion later, 4.4.4 and 5.6.5 are most common)

I have another class which is initialized with a target Canvas which provides 2D raster operations for primitives (point, line, circle, ellipse, triangles and rectangles) as well as several forms of bitBlit operations.

As an aside, I have another class which is initialized with a target Canvas which provides 3d rasterization supporting the usual 3D primitives. Both the 2D and 3D rendering classes can share a single canvas in order to mix 2D and 3D graphics operations.

When a complete scene is drawn, I have another function "Display" (which is the only GDI-specific function) which takes in a handle to the target window and a reference to a source Canvas object. This function builds a DIB pointing to the bitmap data in the Canvas object and then uses the typical Windows double-buffering scheme and GDI's BitBlit function to copy it to the window.

The downside to this method, which may or may not befall GAPI, is that GDI doesn't provide any mechanism to lock onto the vertical sync to avoid shearing. In most cases, shearing shouldn't be that noticeable given the typical screens on mobile devices.


GAPI fails on many devices and was ultimately deprecated largely because many of the (particularly early) VGA landscape devices (such as the first Moto Q) are really just portrait screens tipped on one side. While GAPI itself can be made to cope, the solution is sub-optimal without client-side code changes (particularly, transposing the orientation of source image data) and ultimately this would lend to a poor experience for both devs and users.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this