src/video/x11/SDL_x11events.c
changeset 1178 9867f3d86e44
parent 1168 045f186426e1
child 1179 abb4267e7028
     1.1 --- a/src/video/x11/SDL_x11events.c	Sun Nov 20 23:59:26 2005 +0000
     1.2 +++ b/src/video/x11/SDL_x11events.c	Mon Nov 21 00:16:34 2005 +0000
     1.3 @@ -62,7 +62,7 @@
     1.4  /* The translation tables from an X11 keysym to a SDL keysym */
     1.5  static SDLKey ODD_keymap[256];
     1.6  static SDLKey MISC_keymap[256];
     1.7 -SDL_keysym *X11_TranslateKey(Display *display, XKeyEvent *xkey, KeyCode kc,
     1.8 +SDL_keysym *X11_TranslateKey(Display *display, XIC ic, XKeyEvent *xkey, KeyCode kc,
     1.9  			     SDL_keysym *keysym);
    1.10  
    1.11  /* Check to see if this is a repeated key.
    1.12 @@ -241,7 +241,7 @@
    1.13  #ifdef DEBUG_XEVENTS
    1.14  printf("KeymapNotify!\n");
    1.15  #endif
    1.16 -		X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector);
    1.17 +		X11_SetKeyboardState(SDL_Display, SDL_IC,  xevent.xkeymap.key_vector);
    1.18  	    }
    1.19  	    break;
    1.20  
    1.21 @@ -293,7 +293,7 @@
    1.22  printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
    1.23  #endif
    1.24  		posted = SDL_PrivateKeyboard(SDL_PRESSED,
    1.25 -				X11_TranslateKey(SDL_Display, &xevent.xkey,
    1.26 +				X11_TranslateKey(SDL_Display, SDL_IC, &xevent.xkey,
    1.27  						 xevent.xkey.keycode,
    1.28  						 &keysym));
    1.29  	    }
    1.30 @@ -309,7 +309,7 @@
    1.31  		/* Check to see if this is a repeated key */
    1.32  		if ( ! X11_KeyRepeat(SDL_Display, &xevent) ) {
    1.33  			posted = SDL_PrivateKeyboard(SDL_RELEASED, 
    1.34 -				X11_TranslateKey(SDL_Display, &xevent.xkey,
    1.35 +				X11_TranslateKey(SDL_Display, SDL_IC,  &xevent.xkey,
    1.36  						 xevent.xkey.keycode,
    1.37  						 &keysym));
    1.38  		}
    1.39 @@ -612,7 +612,128 @@
    1.40  	MISC_keymap[XK_Hyper_R&0xFF] = SDLK_MENU;   /* Windows "Menu" key */
    1.41  }
    1.42  
    1.43 -SDL_keysym *X11_TranslateKey(Display *display, XKeyEvent *xkey, KeyCode kc,
    1.44 +#ifdef X_HAVE_UTF8_STRING
    1.45 +Uint32 Utf8ToUcs4(const char * utf8)
    1.46 +{
    1.47 +	Uint32 c;
    1.48 +	int i = 1;
    1.49 +	int noOctets = 0;
    1.50 +	int firstOctetMask = 0;
    1.51 +	unsigned char firstOctet = utf8[0];
    1.52 +	if (firstOctet < 0x80) {
    1.53 +		/*
    1.54 +		  Characters in the range:
    1.55 +		    00000000 to 01111111 (ASCII Range)
    1.56 +		  are stored in one octet:
    1.57 +		    0xxxxxxx (The same as its ASCII representation)
    1.58 +		  The least 6 significant bits of the first octet is the most 6 significant nonzero bits
    1.59 +		  of the UCS4 representation.
    1.60 +		*/
    1.61 +		noOctets = 1;
    1.62 +		firstOctetMask = 0x7F;  /* 0(1111111) - The most significant bit is ignored */
    1.63 +	} else if ((firstOctet & 0xE0) /* get the most 3 significant bits by AND'ing with 11100000 */
    1.64 +	              == 0xC0 ) {  /* see if those 3 bits are 110. If so, the char is in this range */
    1.65 +		/*
    1.66 +		  Characters in the range:
    1.67 +		    00000000 10000000 to 00000111 11111111
    1.68 +		  are stored in two octets:
    1.69 +		    110xxxxx 10xxxxxx
    1.70 +		  The least 5 significant bits of the first octet is the most 5 significant nonzero bits
    1.71 +		  of the UCS4 representation.
    1.72 +		*/
    1.73 +		noOctets = 2;
    1.74 +		firstOctetMask = 0x1F;  /* 000(11111) - The most 3 significant bits are ignored */
    1.75 +	} else if ((firstOctet & 0xF0) /* get the most 4 significant bits by AND'ing with 11110000 */
    1.76 +	              == 0xE0) {  /* see if those 4 bits are 1110. If so, the char is in this range */
    1.77 +		/*
    1.78 +		  Characters in the range:
    1.79 +		    00001000 00000000 to 11111111 11111111
    1.80 +		  are stored in three octets:
    1.81 +		    1110xxxx 10xxxxxx 10xxxxxx
    1.82 +		  The least 4 significant bits of the first octet is the most 4 significant nonzero bits
    1.83 +		  of the UCS4 representation.
    1.84 +		*/
    1.85 +		noOctets = 3;
    1.86 +		firstOctetMask = 0x0F; /* 0000(1111) - The most 4 significant bits are ignored */
    1.87 +	} else if ((firstOctet & 0xF8) /* get the most 5 significant bits by AND'ing with 11111000 */
    1.88 +	              == 0xF0) {  /* see if those 5 bits are 11110. If so, the char is in this range */
    1.89 +		/*
    1.90 +		  Characters in the range:
    1.91 +		    00000001 00000000 00000000 to 00011111 11111111 11111111
    1.92 +		  are stored in four octets:
    1.93 +		    11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    1.94 +		  The least 3 significant bits of the first octet is the most 3 significant nonzero bits
    1.95 +		  of the UCS4 representation.
    1.96 +		*/
    1.97 +		noOctets = 4;
    1.98 +		firstOctetMask = 0x07; /* 11110(111) - The most 5 significant bits are ignored */
    1.99 +	} else if ((firstOctet & 0xFC) /* get the most 6 significant bits by AND'ing with 11111100 */
   1.100 +	              == 0xF8) { /* see if those 6 bits are 111110. If so, the char is in this range */
   1.101 +		/*
   1.102 +		  Characters in the range:
   1.103 +		    00000000 00100000 00000000 00000000 to
   1.104 +		    00000011 11111111 11111111 11111111
   1.105 +		  are stored in five octets:
   1.106 +		    111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
   1.107 +		  The least 2 significant bits of the first octet is the most 2 significant nonzero bits
   1.108 +		  of the UCS4 representation.
   1.109 +		*/
   1.110 +		noOctets = 5;
   1.111 +		firstOctetMask = 0x03; /* 111110(11) - The most 6 significant bits are ignored */
   1.112 +	} else if ((firstOctet & 0xFE) /* get the most 7 significant bits by AND'ing with 11111110 */
   1.113 +	              == 0xFC) { /* see if those 7 bits are 1111110. If so, the char is in this range */
   1.114 +		/*
   1.115 +		  Characters in the range:
   1.116 +		    00000100 00000000 00000000 00000000 to
   1.117 +		    01111111 11111111 11111111 11111111
   1.118 +		  are stored in six octets:
   1.119 +		    1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
   1.120 +		  The least significant bit of the first octet is the most significant nonzero bit
   1.121 +		  of the UCS4 representation.
   1.122 +		*/
   1.123 +		noOctets = 6;
   1.124 +		firstOctetMask = 0x01; /* 1111110(1) - The most 7 significant bits are ignored */
   1.125 +	} else
   1.126 +		return 0;  /* The given chunk is not a valid UTF-8 encoded Unicode character */
   1.127 +	
   1.128 +	/*
   1.129 +	  The least noOctets significant bits of the first octet is the most 2 significant nonzero bits
   1.130 +	  of the UCS4 representation.
   1.131 +	  The first 6 bits of the UCS4 representation is the least 8-noOctets-1 significant bits of
   1.132 +	  firstOctet if the character is not ASCII. If so, it's the least 7 significant bits of firstOctet.
   1.133 +	  This done by AND'ing firstOctet with its mask to trim the bits used for identifying the
   1.134 +	  number of continuing octets (if any) and leave only the free bits (the x's)
   1.135 +	  Sample:
   1.136 +	  1-octet:    0xxxxxxx  &  01111111 = 0xxxxxxx
   1.137 +	  2-octets:  110xxxxx  &  00011111 = 000xxxxx
   1.138 +	*/
   1.139 +	c = firstOctet & firstOctetMask;
   1.140 +	
   1.141 +	/* Now, start filling c.ucs4 with the bits from the continuing octets from utf8. */
   1.142 +	for (i = 1; i < noOctets; i++) {
   1.143 +		/* A valid continuing octet is of the form 10xxxxxx */
   1.144 +		if ((utf8[i] & 0xC0) /* get the most 2 significant bits by AND'ing with 11000000 */
   1.145 +		    != 0x80) /* see if those 2 bits are 10. If not, the is a malformed sequence. */
   1.146 +			/*The given chunk is a partial sequence at the end of a string that could
   1.147 +			   begin a valid character */
   1.148 +			return 0;
   1.149 +		
   1.150 +		/* Make room for the next 6-bits */
   1.151 +		c <<= 6;
   1.152 +		
   1.153 +		/*
   1.154 +		  Take only the least 6 significance bits of the current octet (utf8[i]) and fill the created room
   1.155 +		  of c.ucs4 with them.
   1.156 +		  This done by AND'ing utf8[i] with 00111111 and the OR'ing the result with c.ucs4.
   1.157 +		*/
   1.158 +		c |= utf8[i] & 0x3F;
   1.159 +	}
   1.160 +	return c;
   1.161 +}
   1.162 +#endif
   1.163 +
   1.164 +
   1.165 +SDL_keysym *X11_TranslateKey(Display *display, XIC ic, XKeyEvent *xkey, KeyCode kc,
   1.166  			     SDL_keysym *keysym)
   1.167  {
   1.168  	KeySym xsym;
   1.169 @@ -695,8 +816,7 @@
   1.170  	keysym->unicode = 0;
   1.171  	if ( SDL_TranslateUNICODE && xkey ) {
   1.172  		static XComposeStatus state;
   1.173 -		/* Until we handle the IM protocol, use XLookupString() */
   1.174 -		unsigned char keybuf[32];
   1.175 +
   1.176  
   1.177  #define BROKEN_XFREE86_INTERNATIONAL_KBD
   1.178  /* This appears to be a magical flag that is used with AltGr on
   1.179 @@ -711,15 +831,31 @@
   1.180  		}
   1.181  #endif
   1.182  		/* Look up the translated value for the key event */
   1.183 -		if ( pXLookupString(xkey, (char *)keybuf, sizeof(keybuf),
   1.184 -							NULL, &state) ) {
   1.185 -			/*
   1.186 -			 * FIXME,: XLookupString() may yield more than one
   1.187 -			 * character, so we need a mechanism to allow for
   1.188 -			 * this (perhaps generate null keypress events with
   1.189 -			 * a unicode value)
   1.190 -			 */
   1.191 -			keysym->unicode = keybuf[0];
   1.192 +
   1.193 +		/* if there is no connection with the IM server, use the regular method */
   1.194 +		if (ic == NULL) {
   1.195 +			unsigned char keybuf[32];
   1.196 +
   1.197 +			if ( pXLookupString(xkey, (char *)keybuf, sizeof(keybuf),
   1.198 +								NULL, &state) ) {
   1.199 +				/*
   1.200 +				* FIXME,: XLookupString() may yield more than one
   1.201 +				* character, so we need a mechanism to allow for
   1.202 +				* this (perhaps generate null keypress events with
   1.203 +				* a unicode value)
   1.204 +				*/
   1.205 +				keysym->unicode = keybuf[0];
   1.206 +			}
   1.207 +		} else {  /* else, use the IM protocol */
   1.208 +			#ifdef X_HAVE_UTF8_STRING
   1.209 +			/* A UTF-8 character can be at most 6 bytes */
   1.210 +			unsigned char keybuf[6];
   1.211 +			pXSetICFocus(ic);
   1.212 +			if ( pXutf8LookupString(ic, (XKeyPressedEvent *)xkey, (char *)keybuf, sizeof(keybuf),
   1.213 +			                                    NULL, (Status *)&state) )
   1.214 +				keysym->unicode = Utf8ToUcs4(keybuf);
   1.215 +			pXUnsetICFocus(ic);
   1.216 +			#endif
   1.217  		}
   1.218  	}
   1.219  	return(keysym);
   1.220 @@ -832,12 +968,13 @@
   1.221  	return(unicode);
   1.222  }
   1.223  
   1.224 +
   1.225  /*
   1.226   * Called when focus is regained, to read the keyboard state and generate
   1.227   * synthetic keypress/release events.
   1.228   * key_vec is a bit vector of keycodes (256 bits)
   1.229   */
   1.230 -void X11_SetKeyboardState(Display *display, const char *key_vec)
   1.231 +void X11_SetKeyboardState(Display *display, XIC ic, const char *key_vec)
   1.232  {
   1.233  	char keys_return[32];
   1.234  	int i;
   1.235 @@ -886,7 +1023,7 @@
   1.236  			if(key_vec[i] & (1 << j)) {
   1.237  				SDL_keysym sk;
   1.238  				KeyCode kc = i << 3 | j;
   1.239 -				X11_TranslateKey(display, NULL, kc, &sk);
   1.240 +				X11_TranslateKey(display, ic, NULL, kc, &sk);
   1.241  				new_kstate[sk.sym] = SDL_PRESSED;
   1.242  				xcode[sk.sym] = kc;
   1.243  			}