Page 1 of 1

Q3A for mobiles

Posted: Thu Dec 04, 2008 5:00 pm
by Herr W
Hi everyone!

Don't know if you've already seen this here http://www.symbian-freak.com/downloads/ ... phones.htm. - If not: Mr. Olli Hinkka managed to port Q3A to Symbian OS (S60 3rd Edition, to be precise)! Unfortunately it supports only 3 cellphone types so far, but luckily one of them is mine. :sly: So I was able to test it and - YES - it works! Well done, Olli!

Bad news is, that the game appears almost unplayable with the preset keys. Olli implemented bluetooth keyboard and mouse support to the game, but well, then it's not really "mobile" anymore :rolleyes:

What I think might work could be a combination between the standard directional pad (for moving) and the mobile's build-in 3-axis-accelerometer (for aiming). But I've absolutely no idea how to realise this. Presumably it's not done with something like "bind ACCELEROMETERUP "+forward" in q3config :clownboat:

These guys did something similar on the iPod Touch http://www.youtube.com/watch?v=kvci1vTX ... re=related. In their case the accelerometer works but they use it for moving. And that doesn't look very player-friendly to me as well...

Re: Q3A for mobiles

Posted: Sun Dec 14, 2008 11:23 am
by Herr W
No one? :cry: That's a pity. I'm sure this has a lot of potential...

Unfortunately I'm no coder myself. But I guess this file (named "hidinputmonitor.cpp") has something to do with keyboard input...

Code: Select all

#include "../client/client.h"
#include "symbian_local.h"

#include "hidinputmonitor.h"

extern TPoint currentPosition;

static qboolean shift_down = qfalse;

int hid_to_quake[256] =
    {
    /*  00  */ 000,000,000,000,'a','b','c','d','e','f','g','h','i','j','k','l',
    /*  16  */ 'm','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2',
    /*  32  */ '3','4','5','6','7','8','9','0',K_ENTER,K_ESCAPE,K_BACKSPACE,K_TAB,K_SPACE,'+','´','{',
    /*  48  */ '¨','\'',000,']',000,000,',','.','-',000,000,000,000,000,000,000,
    /*  64  */ 000,000,000,000,000,000,000,000,000,000,000,K_PGUP,K_DEL,000,K_PGDN,K_RIGHTARROW,
    /*  80  */ K_LEFTARROW,K_DOWNARROW,K_UPARROW,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  96  */ 000,000,000,000,'<',000,000,000,000,000,000,000,000,000,000,000,
    /*  112 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  128 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  144 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  160 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  176 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  192 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  208 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  224 */ K_CTRL,K_SHIFT,K_ALT,'~',000,K_SHIFT,000,000,000,000,000,000,000,000,000,000,
    /*  240 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000
    };

int hid_to_quake_shifted[256] = 
    {
    /*  00  */ 000,000,000,000,'A','B','C','D','E','F','G','H','I','J','K','L',
    /*  16  */ 'M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','!','"',
    /*  32  */ '#','¤','%','&','/','(',')','=',K_ENTER,K_ESCAPE,K_BACKSPACE,K_TAB,K_SPACE,'?','\\','}',
    /*  48  */ '^','*',000,'[',000,000,';',':','_',000,000,000,000,000,000,000,
    /*  64  */ 000,000,000,000,000,000,000,000,000,000,000,K_KP_PGUP,K_DEL,000,K_KP_PGDN,K_RIGHTARROW,
    /*  80  */ K_LEFTARROW,K_DOWNARROW,K_UPARROW,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  96  */ 000,000,000,000,'>',000,000,000,000,000,000,000,000,000,000,000,
    /*  112 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  128 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  144 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  160 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  176 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  192 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  208 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  224 */ K_CTRL,K_SHIFT,K_ALT,'~',000,K_SHIFT,000,000,000,000,000,000,000,000,000,000,
    /*  240 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000
    };

//int	hid_to_quake [256] = 
//    {
//    
//    /* 0x00 */	0 /* no event */, 0 /* rollover error */, 0 /* POST fail */,
//    		0 /* undefined error */, 'a', 'b', 'c', 'd',
//    /* 0x08 */	'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
//    /* 0x10 */	'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
//    /* 0x18 */	'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
//    /* 0x20 */	'3', '4', '5', '6', '7', '8', '9', '0',
//    /* 0x28 */	K_ENTER, K_ESCAPE, '\b', K_TAB, K_SPACE, '-', '=', '[',
//    /* 0x30 */	']', '\\', '\\', ';',	'"','~', ',', '.', // '~' was '`'
//    /* 0x38 */	'/', 0, 0, 0, 0, 0, 0, 0,
//    /* 0x40 */	0, 0, 0, 0, 0, 0, 0, 0,
//    /* 0x48 */	K_PAUSE, 0, 0, K_KP_PGUP, K_DEL, 0, K_KP_PGDN, K_RIGHTARROW,
//    /* 0x50 */	K_LEFTARROW, K_DOWNARROW, K_UPARROW, 0, 0, 0, 0, 0,
//    /* 0x58 */	0, 0, 0, 0, 0, 0, 0, 0,
//    /* 0x60 */	0, 0, 0, 0, 0, 0, 0, 0,
//    /* pmk!! fill these in, even though my keyboard doesn't use them... */
//    /* 0x68 */	0, 0, 0, 0, 0, 0, 0, 0,
//    /* 0x70 */	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
//    /* 0x80 */	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
//    /* 0x90 */	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
//    /* 0xa0 */	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
//    /* 0xb0 */	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
//    /* 0xc0 */	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
//    /* 0xd0 */	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
//    /* 0xe0 */	K_CTRL, K_SHIFT, K_ALT,
//    		0,	/* Would COMPOSE be better? */
//    		K_CTRL, K_SHIFT, K_ALT, 0,
//    /* 0xe8 */	0, 0, 0, 0, 0, 0, 0, 0,
//    /* 0xf0 */	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
//    };


void CHIDEventMonitor::RunL()
    {
    THIDEvent hidEvent;
    iHIDClient->GetEvent( hidEvent );
    switch (hidEvent.Type())
        {
        case THIDEvent::EMouseEvent:
            {
            TMouseEvent* mouse = hidEvent.Mouse();
            switch (mouse->Type())
                {
                case EEventRelativeXY:
                    currentPosition += mouse->iPosition;
                    break;
                case EEventButtonDown:
                    switch(mouse->iValue)
                        {
                        case EMouseButtonLeft:
                            Sys_QueEvent(0, SE_KEY, K_MOUSE1, qtrue, 0, NULL);
                            break;
                        case EMouseButtonRight:
                            Sys_QueEvent(0, SE_KEY, K_MOUSE2, qtrue, 0, NULL);
                            break;
                        case EMouseButtonMiddle:
                            Sys_QueEvent(0, SE_KEY, K_MOUSE3, qtrue, 0, NULL);
                            break;
                        default:
                            break;
                        }
                    break;
                case EEventButtonUp:
                    switch(mouse->iValue)
                        {
                        case EMouseButtonLeft:
                            Sys_QueEvent(0, SE_KEY, K_MOUSE1, qfalse, 0, NULL);
                            break;
                        case EMouseButtonRight:
                            Sys_QueEvent(0, SE_KEY, K_MOUSE2, qfalse, 0, NULL);
                            break;
                        case EMouseButtonMiddle:
                            Sys_QueEvent(0, SE_KEY, K_MOUSE3, qfalse, 0, NULL);
                            break;
                        default:
                            break;
                        }
                    break;
                case EEventRelativeWheel:
                    if (mouse->iValue > 0)
                        {
                        Sys_QueEvent(0, SE_KEY, K_MWHEELUP, qtrue, 0, NULL );
                        Sys_QueEvent(0, SE_KEY, K_MWHEELUP, qfalse, 0, NULL );
                        }
                    else
                        {
                        Sys_QueEvent(0, SE_KEY, K_MWHEELDOWN, qtrue, 0, NULL );
                        Sys_QueEvent(0, SE_KEY, K_MWHEELDOWN, qfalse, 0, NULL );
                        }
                    break;
                default:
                    break;
                }
            }
            break;
        case THIDEvent::EKeyEvent:
            {
            THIDKeyEvent* key = hidEvent.Key();
            int hid_code = hid_to_quake[key->ScanCode()];
            switch (key->Type())
                {
                case EEventHIDKeyUp:
                    if (hid_code == K_SHIFT)
                        {
                        shift_down = qfalse;
                        }
                    Sys_QueEvent(0, SE_KEY,  hid_code, qfalse, 0, NULL );
                    
                    break;
                case EEventHIDKeyDown:
//                    Com_Printf( "EEventHIDKeyDown, code %d\n",key->ScanCode());
                    if (hid_code == K_SHIFT)
                        {
                        shift_down = qtrue;
                        }
                    Sys_QueEvent(0, SE_KEY,  hid_code, qtrue, 0, NULL );
                    if (shift_down)
                        {
                        hid_code = hid_to_quake_shifted[key->ScanCode()];
                        }
                    if (hid_code <= 127)
                        {
                        if (hid_code == K_BACKSPACE)
                            {
                            hid_code = '\b';
                            }
                        Sys_QueEvent(0, SE_CHAR, hid_code, 0, 0, NULL );
                        }
                    break;
                default:
                    break;
                }
            }
            break;
        case THIDEvent::EConsumerEvent:
            {
            THIDConsumerEvent* consumer = hidEvent.Consumer();
            Com_Printf( "consumer, code %d\n",consumer->ButtonCode());
            break;
            }
        default:
            break;
        }
    iHIDClient->EventReady( &iStatus );
    SetActive();
    }
    
void CHIDEventMonitor::DoCancel()
    {
    iHIDClient->EventReadyCancel();
    }

CHIDEventMonitor* CHIDEventMonitor::NewL()
    {
    CHIDEventMonitor* self = new (ELeave) CHIDEventMonitor;
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop();
    return self;
    }

CHIDEventMonitor::~CHIDEventMonitor()
    {
    Cancel();
    delete iHIDClient;
    }

CHIDEventMonitor::CHIDEventMonitor() 
        :CActive(CActive::EPriorityIdle)
    {
    }
        
void CHIDEventMonitor::ConstructL()
    {
    User::LeaveIfError(iHidLibrary.Load(_L("hidsrv.dll")));
    TLibraryFunction entry = iHidLibrary.Lookup(1);
    if (entry)
        {
        iHIDClient = (MHIDSrvClient*) entry();
        if (iHIDClient)
            {
            User::LeaveIfError(iHIDClient->Connect());
            iHIDClient->EventReady( &iStatus );
            CActiveScheduler::Add( this );
            SetActive();
            }
        }
    else
        {
        User::Leave(KErrNotFound);
        }
    }
... And this part of the code (named "symbian_input.cpp") seems to contain things related to mouse control (which I would like to replace by the motion sensor):

Code: Select all

#include "../client/client.h"
#include "symbian_local.h"
#include <e32base.h>
#include "hidinputmonitor.h"

CHIDEventMonitor* theHIDMonitor = NULL;
TPoint currentPosition(0,0);
qboolean mouseactive;

void IN_Init( void ) 
    {
    Com_Printf( "Input initialization...\n" );
    Com_Printf( "  ... Connecting to HID server & creating event listener\n" );
    TRAPD(err, theHIDMonitor = CHIDEventMonitor::NewL());
    if (err)
        {
        Com_Printf( "  ... Failed with error %d\n", err );    
        }
    else
        {
        Com_Printf( "  ... HID server connected, listening for events\n", err );    
        }
    currentPosition = TPoint( cls.glconfig.vidWidth /2, cls.glconfig.vidHeight /2);
    mouseactive = qtrue;
    Com_Printf( "Input initializarion complete\n");    
    }

void IN_MouseMove()
    {
    int	mx, my;

    // don't bother sending events it mouse is not active or has not moved...
    if (!mouseactive || 
        currentPosition == TPoint( cls.glconfig.vidWidth /2, cls.glconfig.vidHeight /2))
		return;

	
	mx = currentPosition.iX - cls.glconfig.vidWidth /2;
	my = currentPosition.iY - cls.glconfig.vidHeight /2;

    // this can possibly crash the game if called too early in init...
   	Sys_QueEvent( 0, SE_MOUSE, mx, my, 0, NULL ); 

    currentPosition = TPoint( cls.glconfig.vidWidth /2, cls.glconfig.vidHeight /2);
    }

void IN_Frame (void) 
    {
    IN_MouseMove();
    }

void IN_Shutdown( void ) 
    {
    mouseactive = qfalse;
    delete theHIDMonitor;
    }

void Sys_SendKeyEvents (void) 
    {
    }
Oh, and this here looks interesting, too ("wseventhandler.cpp"):

Code: Select all

#include <w32std.h>
#include <aknutils.h>
#include <aknutils.h>

#include "../renderer/tr_local.h"
#include "../ui/keycodes.h"
#include "../client/client.h"
#include "symbian_local.h"

#include "multitaptranslator.h"

extern TBool windowCreated;
extern int appOnBackground;
extern RWindow wsWindow;

extern CMultitapKeyTranslator* theKeyTranslator;

// missing ö,ä,å,chr

static qboolean shift_down = qfalse;

int scan_to_quake[256] =
    {
    /*  00  */ 000,K_BACKSPACE,K_TAB,K_ENTER,000,K_SPACE,000,000,000,000,000,000,000,000,K_LEFTARROW,K_RIGHTARROW,
    /*  16  */ K_UPARROW,K_DOWNARROW,K_SHIFT,K_SHIFT,000,000,K_CTRL,000,000,000,000,000,000,000,000,000,
    /*  32  */ 000,000,000,000,000,000,000,000,000,000,000,'+',000,000,000,000,
    /*  48  */ '0','1','2','3','4','5','6','7','8','9',000,000,000,000,000,000,
    /*  64  */ 000,'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
    /*  80  */ 'p','q','r','s','t','u','v','w','x','y','z',000,000,000,000,000,
    /*  96  */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  112 */ 000,000,000,000,000,000,000,000,000,',','.',000,'<',000,000,'\'',
    /*  128 */ '\\',000,'-',000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  144 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  160 */ 000,000,000,000,K_ENTER,K_ESCAPE,000,K_KP_ENTER,000,000,000,000,000,000,000,000,
    /*  176 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  192 */ 000,000,000,000,'~',000,000,000,000,000,000,000,000,000,000,000,
    /*  208 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  224 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  240 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000
    };

int scan_to_quake_shifted[256] =
    {
    /*  00  */ 000,K_BACKSPACE,K_TAB,K_ENTER,000,K_SPACE,000,000,000,000,000,000,000,000,K_LEFTARROW,K_RIGHTARROW,
    /*  16  */ K_UPARROW,K_DOWNARROW,K_SHIFT,K_SHIFT,000,000,K_CTRL,000,000,000,000,000,000,000,000,000,
    /*  32  */ 000,000,000,000,000,000,000,000,000,000,000,'?',000,000,000,000,
    /*  48  */ '=','!','"','#','$','%','&','/','(',')',000,000,000,000,000,000,
    /*  64  */ 000,'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
    /*  80  */ 'P','Q','R','S','T','U','V','W','X','Y','Z',000,000,000,000,000,
    /*  96  */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  112 */ 000,000,000,000,000,000,000,000,000,';',':',000,'>',000,000,'*',
    /*  128 */ '|',000,'_',000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  144 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  160 */ 000,000,000,000,K_ENTER,K_ESCAPE,000,K_KP_ENTER,000,000,000,000,000,000,000,000,
    /*  176 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  192 */ 000,000,000,000,'~',000,000,000,000,000,000,000,000,000,000,000,
    /*  208 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  224 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,
    /*  240 */ 000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000
    };



int MapKey (int code)
    {
    switch (code)
        {
        case EStdKeyLeftArrow: return K_LEFTARROW;
        case EStdKeyRightArrow: return K_RIGHTARROW;
	    case EStdKeyUpArrow: return K_UPARROW;
	    case EStdKeyDownArrow: return K_DOWNARROW;
        case EStdKeyDevice1: return K_ESCAPE;
	    case EStdKeyDevice0: return K_ENTER;
	    case EStdKeyDevice3: return 'f';
	    case 1: return K_BACKSPACE;
        case EStdKeyHash: return K_TAB;
        case 42: return '~';
        case 48: return '0';
        case 49: return '1';
        case 50: return '2';
        case 51: return '3';
        case 52: return '4';
        case 53: return '5';
        case 54: return '6';
        case 55: return '7';
        case 56: return '8';
        case 57: return '9';
        case EStdKeyApplication19: return 'c'; // camera key
        case EStdKeyLeftShift: return 's'; // pen key
        case EStdKeyYes: return 'y'; // call answer key
	    default: return 0;
        }
    }



TBool IsQwerty()
    {
    if (cls.glconfig.vidWidth == 800 &&
        cls.glconfig.vidHeight == 352)
        {
        return ETrue;
        }
    return EFalse;
    }

void HandleWsEvent( const TWsEvent& aWsEvent )
    {
    TInt eventType = aWsEvent.Type();
    TBool down = EFalse;
    TKeyEvent* event;

    switch( eventType )
        {
        case EEventKeyDown:
            {
            //Com_Printf( "scancode, code %d\n",aWsEvent.Key()->iScanCode);
            down = ETrue;
            } // fall through
        case EEventKeyUp:
            {
            TInt scan = 0;
            TBool isqwerty = IsQwerty();
            event = aWsEvent.Key();
            if (isqwerty)
                {
                if (shift_down)
                    {
                    scan = scan_to_quake_shifted[event->iScanCode&0xff];
                    }
                else
                    {
                    scan = scan_to_quake[event->iScanCode&0xff];
                    }
                if (scan == K_SHIFT)
                   {
                   shift_down = (qboolean)down;
                   }
                }
            else
                {
                scan = MapKey(event->iScanCode);
                }
            TBool replace = EFalse;
            // console and ui should be able to receive text typed by the phone keys..
            // also, this statement should check whether we are (re)configuring the keys..
            if (!isqwerty && ((cls.keyCatchers & KEYCATCH_CONSOLE) || (cls.keyCatchers & KEYCATCH_UI)))
                {
                if (cls.keyCatchers & KEYCATCH_UI && !(cls.keyCatchers & KEYCATCH_CONSOLE))
                    {
                    replace = ETrue;
                    }
                // ui uses always replace mode???
                theKeyTranslator->TranslateAndSendKey(event->iScanCode,down, replace);
                }
            // no typing needed in the game or when (re)configuring the keys
            else if (down)
                {
                Sys_QueEvent(0, SE_KEY, scan ,qtrue,0,NULL);                
                if (isqwerty && scan <= 127)
                    {
                    if (scan == K_BACKSPACE)
                        {
                        scan = '\b';
                        }
                    Sys_QueEvent(0, SE_CHAR, scan, 0, 0, NULL );
                    }
                }
            else
                {
                Sys_QueEvent(0, SE_KEY, scan ,qfalse,0,NULL);
                }            
            break;
            }
            
        case EEventScreenDeviceChanged:
            {
            if (windowCreated)
                {
                CWsScreenDevice* screenDev = CCoeEnv::Static()->ScreenDevice();
                TPixelsTwipsAndRotation rot;
                screenDev->GetScreenModeSizeAndRotation(screenDev->CurrentScreenMode(),rot);
                TSize displaySize = rot.iPixelSize;
            	wsWindow.SetSize(displaySize);
            	wsWindow.SetExtent(TPoint(0,0),displaySize);
                glConfig.vidWidth = displaySize.iWidth;
                glConfig.vidHeight = displaySize.iHeight;    
                cls.glconfig = glConfig;
                if (cls.uiStarted)
                    {
                    VM_Call(uivm, UI_UPDATE_GLCONFIG);
                    }
                if (cls.state == CA_ACTIVE)
                    {
                    VM_Call(cgvm, CG_UPDATE_GLCONFIG);
                    }
                }
            break;                    
            }
        case EEventFocusLost:
            {
            appOnBackground = 1;
            break;
            }
        case EEventFocusGained:
            {
            appOnBackground = 0;
            SetKeyblockMode( ENoKeyBlock );
            break; 
            }            
        default:
            break;
        }        
    }
As I said, this is all Geek to me :confused: , but maybe not to an experienced coder. - I'd really appreciate if someone can help me on this!!!

Re: Q3A for mobiles

Posted: Mon Dec 15, 2008 9:23 am
by ^misantropia^
Can't help you, I'm afraid. You might have more luck on one of the Symbian or general mobile development forums.

Re: Q3A for mobiles

Posted: Tue Jan 13, 2009 9:52 am
by Herr W
If anyone else is interested in this: It's discussed here http://www.symbian-freak.com/forum/view ... e5e495705f