• ### What is your GameDev Story?

This topic is 4905 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I'm trying to figure out how to get lower and uppercase without a dodgy if shift +(number) hack stuff. 'A' and 'a' are both the same apparently.. So guys, how did you get it to let you have caps and lower case?

##### Share on other sites
In what context are you talking about? Are you asking about how to map key codes into character values from keyboard input? If so, what programming language are you using and what input API?

##### Share on other sites
Ugg, sorry.. I'm used to posting stuff under the OpenGL board. It's C++, OpenGL.. currently I use the 'VK_TAB' or 'A' from the wParam in the main loop to register key strokes.

What I'm asking is how to make it so I get uppercase and lowercase keys, currently it all goes to uppercase (A = A and a = a.. but there is no a).

##### Share on other sites
clicky for DirectX
The (ugly) code below works for me(win32)

/////////////////////////////////////////////////////////////////////////////////////////////////////////////		VK2char//			WndProc helping function//			converts the VK to a char///////////////////////////////////////////////////////////////////////////////////////////////////////////// returns 0 if genesis3d(my current engine) doesn't accept the parameter, returns c if it doeschar getAllowedAscii(char c){	if( 0x20 <= c )	{		if( c <= 0x7e )		{			return c;		}	}		if( c == 0x08 ) return c; // backspace		return 0;}/**MsVC++ gave some compiler errors and warnings on this piece of code I gotfrom gamedev.net, probably sincethe code was written for DirectInput which gets scancodes. I on the otherhand get virtual key codes.I fixed them, but I wonder if it a nice fix or a hack fix. I hope it'sthe first.In case anyone wonder here's the url where I got the :http://www.gamedev.net/reference/programming/features/scan2asc/**/static int scan2ascii(DWORD scancode, USHORT* result){    WPARAM vk;	static unsigned char State[256];	HKL layout=GetKeyboardLayout(0);			if (GetKeyboardState(State)==FALSE)		return 0;	vk=MapVirtualKeyEx(scancode,1,layout);	return ToAsciiEx(vk,scancode,State,result,0,layout);}char VK2char(WPARAM vk){	int r;	unsigned short c[2];		if( vk == VK_RETURN ) return '\n';// return key is pressed		vk = MapVirtualKey(vk, 0);	if( vk == 0 ) return 0;		r = scan2ascii( vk, c);		if( r )	{		if( c[0] > 255 ) return 0; // we don't want to use			// characters outside of the char range		return getAllowedAscii( (char) c[0] );	}	return 0;}

edit: fixed newlines

##### Share on other sites
I guess you should test for VK_SHIFT to know the difference between a "A" keystroke that's upper or lower case? I guess its VK_CAPITAL to know if Caps Lock is on.

Hope this helps

Eric

##### Share on other sites
Quote:
 Original post by BorukiI'm trying to figure out how to get lower and uppercase without a dodgy if shift +(number) hack stuff.'A' and 'a' are both the same apparently.. So guys, how did you get it to let you have caps and lower case?

There are essentially three ways to do it. I actually wrote an entry in my blog about this, including a bleeding-edge MMX version of strupr (which converts 8 characters at a time, and is several times faster than other methods).

##### Share on other sites
Quote:
 I actually wrote an entry in my blog about this, including a bleeding-edge MMX version of strupr (which converts 8 characters at a time, and is several times faster than other methods).

To refresh MMX skillz, had a look at this and it is possible to go a bit faster :)
; setup	movq	CONST_Z, [z_1]	movq	CONST_A, [a_1]	movq	CONST_DELTA, [delta]; process 8 chars	movq	CHARS, [src_chars]	movq	Z_MASK, CONST_Z	movq	A_MASK, CHARS	pcmpgtb A_MASK, CONST_A	pcmpgtb Z_MASK, CHARSMASK := A_MASK	pand	MASK, Z_MASK	pand	MASK, CONST_DELTA	psub	CHARS, MASK		; mmx doesn't support load-execute-store arithmetic	movq	[dst_chars], CHARS

We need 9 MMX instructions per block instead of 13.
The uppercase symbols are registers and can be allocated as desired. General tip on MMX: put constants in memory, load them before looping and keep in registers. You have 8 - use 'em! :)

##### Share on other sites
Quote:
 Original post by Jan WassenbergTo refresh MMX skillz, had a look at this and it is possible to go a bit faster :)*** Source Snippet Removed ***We need 9 MMX instructions per block instead of 13.The uppercase symbols are registers and can be allocated as desired. General tip on MMX: put constants in memory, load them before looping and keep in registers. You have 8 - use 'em! :)

While it's true that you could improve the speed of my code by a few cycles by keeping the masks in spare MMX registers, your code is actually a full 5 cycles slower in the loop than mine, due to poor instruction ordering and the use of movq. movq has 6 cycles of latency, compared to pshufw's 2, which is why I used pshufw in such a contorted way.

##### Share on other sites
Oh goody, am refreshing pipeline sim skillz as well :)

Quote:
 your code is actually a full 5 cycles slower in the loop than mine, due to poor instruction ordering and the use of movq. movq has 6 cycles of latency, compared to pshufw's 2, which is why I used pshufw in such a contorted way.

A "full" 5 clocks slower? No, sir. First, instructions are reordered automatically according to which of their dependencies completes, so that is not an issue. Oh, you're on a P4, right? My sympathies :P I write for Athlon, where MOVQ is 2 clocks (+2 for L1 access), as it should be :)

So let's look at instruction flow. After incorporating a little trick (prefetch), this runs in 10 clocks:
pcmpgtb	A_MASK, CONST_Amovq	PREFETCH_CHARS, [next_src_chars]	// potential problem: read beyond end of bufferpcmpgtb	Z_MASK, CHARSnoppand	A_MASK, Z_MASKmovq	Z_MASK, CONST_Znoppand	A_MASK, CONST_DELTAnoppsub	CHARS, A_MASK; mmx doesn't support load-execute-store arithmeticmovq	A_MASK, PREFETCH_CHARSnopmovq	[dst_chars], CHARSmovq	CHARS, PREFETCH_CHARSjmp	loop

Your code as written requires 15:
movq	mm1, [edx] ; the packed charactersmovd	mm2, eax		// vector decode :(movd	mm3, ebxnopmovq	mm0, mm1pshufw	mm4, mm2, 00000000b ; the lower bounds maskpshufw	mm2, mm2, 01010101b ; the upper bounds maskpshufw	mm3, mm3, 00000000b ; the subtraction maskpcmpgtb	mm1, mm4pcmpgtb	mm2, mm0noppand	mm3, mm1noppand	mm3, mm2noppsubb	mm0, mm3nopmovq	[edx], mm0jmp

Surprisingly, the extra instructions turn out not to really affect performance but of course make interleaving harder. What really ends up hurtin' is MOVD, which is penalized on Athlon (3 clock latency and blocks the pipe).

@OP: sorry for hijacking the thread :)

##### Share on other sites
What message are you using?

WM_KEYDOWN tells you what that a key was pressed and tells you which key.

WM_CHAR tells you which character that a pressed key represents - which obviously changes due to localisation issues and keyboard starte (what other keys are held down etc.)

• ### What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 10
• 11
• 13
• 9
• 11
• ### Forum Statistics

• Total Topics
634090
• Total Posts
3015432
×