[PATCH] API to enable caps lock/num lock release events

[Trying to send this again. Sorry for any repeats.]

Hi,

I’m new here, so apologies in advance if this is slightly clueless (I’m
not sure if/how often this issue has come up before!).

For a little program I’m porting (back to!) to Linux just for fun,
it’d be really handy to have caps lock (and num lock, but that’s not
so immediately pressing for me) treated like an ordinary key (*). I
assume the vast majority of machines can handle this from an OS/hardware
perspective, so it seems a little strange to me for there to be no way
of enabling this functionality in SDL.

So, this patch adds an API:

int SDL_EnableLockKeyRelease(int enable);

with fairly similar semantics to SDL_EnableUNICODE: 1 to enable the
feature, 0 to disable it, -1 to just read previous value. So, e.g.,
I can put at the start of my program:

SDL_EnableLockKeyRelease(SDL_TRUE);

and then caps lock & num lock will behave “as expected”.

I’ve tested on a grand total of one machine type, x86/Linux with X11.
Please feel free to reformat/rewrite/augment the patch if necessary!

Cheers,

Julian

(*) It’s a micro emulator, so needs fairly raw keyboard input. A quick
web search seemed to reveal other people had encountered similar
problems, but I couldn’t find any existing solutions.

-------------- next part --------------
diff -urp …/SDL-1.2a/include/SDL_keyboard.h ./include/SDL_keyboard.h
— …/SDL-1.2a/include/SDL_keyboard.h 2005-09-04 01:05:52.000000000 +0100
+++ ./include/SDL_keyboard.h 2005-09-04 00:54:17.000000000 +0100
@@ -90,6 +90,16 @@ extern DECLSPEC int SDLCALL SDL_EnableUN
extern DECLSPEC int SDLCALL SDL_EnableKeyRepeat(int delay, int interval);

/*

    • Allow generation of release events for the caps lock and num lock keys, if
    • the hardware/OS supports it.
    • If ‘enable’ is 1, release events are enabled.
    • If ‘enable’ is 0, release events are disabled.
    • If ‘enable’ is -1, the release event behaviour is not changed.
    • It returns the previous state of caps lock and num lock release enabling.
  • /
    +extern DECLSPEC int SDLCALL SDL_EnableLockKeyRelease(int enable);+
    +/
    • Get a snapshot of the current state of the keyboard.
    • Returns an array of keystates, indexed by the SDLK_* syms.
    • Used:
      diff -urp …/SDL-1.2a/src/events/SDL_keyboard.c ./src/events/SDL_keyboard.c
      — …/SDL-1.2a/src/events/SDL_keyboard.c 2005-09-04 01:06:04.000000000 +0100
      +++ ./src/events/SDL_keyboard.c 2005-09-04 00:59:17.000000000 +0100
      @@ -43,6 +43,7 @@ static char rcsid =
      static Uint8 SDL_KeyState[SDLK_LAST];
      static SDLMod SDL_ModState;
      int SDL_TranslateUNICODE = 0;
      +int SDL_LockReleaseEnabled = 0;

static char keynames[SDLK_LAST]; / Array of keycode names */

@@ -400,16 +401,24 @@ printf(“The ‘%s’ key has been %s\n”, SDL
keysym->mod = (SDLMod)modstate;
switch (keysym->sym) {
case SDLK_NUMLOCK:

  •   		modstate ^= KMOD_NUM;
    
  •   		if ( ! (modstate&KMOD_NUM) )
    
  •   			state = SDL_RELEASED;
    
  •   		keysym->mod = (SDLMod)modstate;
    
  •                            if (SDL_LockReleaseEnabled) {
    
  •                            	modstate |= KMOD_NUM;
    
  •                            } else {
    
  •   			modstate ^= KMOD_NUM;
    
  •   			if ( ! (modstate&KMOD_NUM) )
    
  •   				state = SDL_RELEASED;
    
  •   			keysym->mod = (SDLMod)modstate;
    
  •   		}
      		break;
      	case SDLK_CAPSLOCK:
    
  •   		modstate ^= KMOD_CAPS;
    
  •   		if ( ! (modstate&KMOD_CAPS) )
    
  •   			state = SDL_RELEASED;
    
  •   		keysym->mod = (SDLMod)modstate;
    
  •                    	if (SDL_LockReleaseEnabled) {
    
  •                            	modstate |= KMOD_CAPS;
    
  •                            } else {
    
  •   			modstate ^= KMOD_CAPS;
    
  •   			if ( ! (modstate&KMOD_CAPS) )
    
  •   				state = SDL_RELEASED;
    
  •   			keysym->mod = (SDLMod)modstate;
    
  •                            }
      		break;
      	case SDLK_LCTRL:
      		modstate |= KMOD_LCTRL;
    

@@ -445,9 +454,19 @@ printf(“The ‘%s’ key has been %s\n”, SDL
} else {
switch (keysym->sym) {
case SDLK_NUMLOCK:

  •                    	if (SDL_LockReleaseEnabled) {
    
  •                            	modstate &= ~KMOD_NUM;
    
  •   		} else {
    
  •   			/* Only send keydown events */
    
  •                            	return(0);
    
  •                            }
      	case SDLK_CAPSLOCK:
    
  •   		/* Only send keydown events */
    
  •   		return(0);
    
  •                    	if (SDL_LockReleaseEnabled) {
    
  •                            	modstate &= ~KMOD_CAPS;
    
  •   		} else {
    
  •   			/* Only send keydown events */
    
  •                            	return(0);
    
  •                            }
      	case SDLK_LCTRL:
      		modstate &= ~KMOD_LCTRL;
      		break;
    

@@ -570,3 +589,22 @@ int SDL_EnableKeyRepeat(int delay, int i
return(0);
}

+int SDL_EnableLockKeyRelease(int enable)
+{

  • int oldval = SDL_LockReleaseEnabled;
  • switch (enable) {
  •            case -1:
    
  •            break;
    
  •    	case 0:
    
  •            case 1:
    
  •            SDL_LockReleaseEnabled = enable;
    
  •            break;
    
  •            default:
    
  •            SDL_SetError("bad value for EnableLockRelease");
    
  •            return(-1);
    
  • }
  •    return(oldval);
    

+}

…and here’s a version with slightly fewer obvious bugs up-front (I
missed two break statements and spelled the error message wrong…).

Cheers,

Julian
-------------- next part --------------
diff -urp …/SDL-1.2a/include/SDL_keyboard.h ./include/SDL_keyboard.h
— …/SDL-1.2a/include/SDL_keyboard.h 2005-09-04 01:05:52.000000000 +0100
+++ ./include/SDL_keyboard.h 2005-09-04 00:54:17.000000000 +0100
@@ -90,6 +90,16 @@ extern DECLSPEC int SDLCALL SDL_EnableUN
extern DECLSPEC int SDLCALL SDL_EnableKeyRepeat(int delay, int interval);

/*

    • Allow generation of release events for the caps lock and num lock keys, if
    • the hardware/OS supports it.
    • If ‘enable’ is 1, release events are enabled.
    • If ‘enable’ is 0, release events are disabled.
    • If ‘enable’ is -1, the release event behaviour is not changed.
    • It returns the previous state of caps lock and num lock release enabling.
  • */
    +extern DECLSPEC int SDLCALL SDL_EnableLockKeyRelease(int enable);On Sun, Sep 04, 2005 at 02:23:37PM +0100, Julian Brown wrote:

So, this patch adds an API:

int SDL_EnableLockKeyRelease(int enable);

with fairly similar semantics to SDL_EnableUNICODE: 1 to enable the
feature, 0 to disable it, -1 to just read previous value. So, e.g.,
I can put at the start of my program:

SDL_EnableLockKeyRelease(SDL_TRUE);

and then caps lock & num lock will behave “as expected”.

I’ve tested on a grand total of one machine type, x86/Linux with X11.
Please feel free to reformat/rewrite/augment the patch if necessary!

+/*

  • Get a snapshot of the current state of the keyboard.
  • Returns an array of keystates, indexed by the SDLK_* syms.
  • Used:
    diff -urp …/SDL-1.2a/src/events/SDL_keyboard.c ./src/events/SDL_keyboard.c
    — …/SDL-1.2a/src/events/SDL_keyboard.c 2005-09-04 01:06:04.000000000 +0100
    +++ ./src/events/SDL_keyboard.c 2005-09-04 15:17:19.000000000 +0100
    @@ -43,6 +43,7 @@ static char rcsid =
    static Uint8 SDL_KeyState[SDLK_LAST];
    static SDLMod SDL_ModState;
    int SDL_TranslateUNICODE = 0;
    +int SDL_LockReleaseEnabled = 0;

static char keynames[SDLK_LAST]; / Array of keycode names */

@@ -400,16 +401,24 @@ printf(“The ‘%s’ key has been %s\n”, SDL
keysym->mod = (SDLMod)modstate;
switch (keysym->sym) {
case SDLK_NUMLOCK:

  •   		modstate ^= KMOD_NUM;
    
  •   		if ( ! (modstate&KMOD_NUM) )
    
  •   			state = SDL_RELEASED;
    
  •   		keysym->mod = (SDLMod)modstate;
    
  •                            if (SDL_LockReleaseEnabled) {
    
  •                            	modstate |= KMOD_NUM;
    
  •                            } else {
    
  •   			modstate ^= KMOD_NUM;
    
  •   			if ( ! (modstate&KMOD_NUM) )
    
  •   				state = SDL_RELEASED;
    
  •   			keysym->mod = (SDLMod)modstate;
    
  •   		}
      		break;
      	case SDLK_CAPSLOCK:
    
  •   		modstate ^= KMOD_CAPS;
    
  •   		if ( ! (modstate&KMOD_CAPS) )
    
  •   			state = SDL_RELEASED;
    
  •   		keysym->mod = (SDLMod)modstate;
    
  •                    	if (SDL_LockReleaseEnabled) {
    
  •                            	modstate |= KMOD_CAPS;
    
  •                            } else {
    
  •   			modstate ^= KMOD_CAPS;
    
  •   			if ( ! (modstate&KMOD_CAPS) )
    
  •   				state = SDL_RELEASED;
    
  •   			keysym->mod = (SDLMod)modstate;
    
  •                            }
      		break;
      	case SDLK_LCTRL:
      		modstate |= KMOD_LCTRL;
    

@@ -445,9 +454,21 @@ printf(“The ‘%s’ key has been %s\n”, SDL
} else {
switch (keysym->sym) {
case SDLK_NUMLOCK:

  •                    	if (SDL_LockReleaseEnabled) {
    
  •                            	modstate &= ~KMOD_NUM;
    
  •   		} else {
    
  •   			/* Only send keydown events */
    
  •                            	return(0);
    
  •                            }
    
  •                            break;
      	case SDLK_CAPSLOCK:
    
  •   		/* Only send keydown events */
    
  •   		return(0);
    
  •                    	if (SDL_LockReleaseEnabled) {
    
  •                            	modstate &= ~KMOD_CAPS;
    
  •   		} else {
    
  •   			/* Only send keydown events */
    
  •                            	return(0);
    
  •                            }
    
  •                            break;
      	case SDLK_LCTRL:
      		modstate &= ~KMOD_LCTRL;
      		break;
    

@@ -570,3 +591,22 @@ int SDL_EnableKeyRepeat(int delay, int i
return(0);
}

+int SDL_EnableLockKeyRelease(int enable)
+{

  • int oldval = SDL_LockReleaseEnabled;
  • switch (enable) {
  •            case -1:
    
  •            break;
    
  •    	case 0:
    
  •            case 1:
    
  •            SDL_LockReleaseEnabled = enable;
    
  •            break;
    
  •            default:
    
  •            SDL_SetError("bad value for EnableLockKeyRelease");
    
  •            return(-1);
    
  • }
  •    return(oldval);
    

+}

For a little program I’m porting (back to!) to Linux just for fun,
it’d be really handy to have caps lock (and num lock, but that’s not
so immediately pressing for me) treated like an ordinary key (*). I
assume the vast majority of machines can handle this from an OS/hardware
perspective, so it seems a little strange to me for there to be no way
of enabling this functionality in SDL.

I forget offhand which platforms have problems with it, but I think one
or more of them can’t handle those keys like normal keys. Windows might
be one of them…

-Sam Lantinga, Software Engineer, Blizzard Entertainment