client: KeyHandler now receive unicode char event in addition to RedKey events

This commit is contained in:
Yaniv Kamay 2009-11-21 19:28:59 +02:00
parent 81241dd825
commit 6c5966d8ed
11 changed files with 147 additions and 3 deletions

View File

@ -907,7 +907,12 @@ void Application::on_key_up(RedKey key)
}
do_on_key_up(key);
}
}
void Application::on_char(uint32_t ch)
{
_key_handler->on_char(ch);
}
void Application::on_deactivate_screen(RedScreen* screen)
{

View File

@ -131,6 +131,7 @@ public:
void on_mouse_up(int button, int buttons_state);
void on_key_down(RedKey key);
void on_key_up(RedKey key);
void on_char(uint32_t ch);
void on_deactivate_screen(RedScreen* screen);
void on_activate_screen(RedScreen* screen);
void on_start_screen_key_interception(RedScreen* screen);

View File

@ -25,6 +25,7 @@ public:
virtual ~KeyHandler() {}
virtual void on_key_down(RedKey key) {}
virtual void on_key_up(RedKey key) {}
virtual void on_char(uint32_t ch) {}
virtual void on_focus_in() {}
virtual void on_focus_out() {}
virtual bool permit_focus_loss() { return true;}

View File

@ -126,6 +126,7 @@ public:
virtual void on_key_press(RedKey key) = 0;
virtual void on_key_release(RedKey key) = 0;
virtual void on_char(uint32_t ch) = 0;
virtual void on_deactivate() = 0;
virtual void on_activate() = 0;

View File

@ -659,6 +659,11 @@ void RedScreen::on_key_release(RedKey key)
_owner.on_key_up(key);
}
void RedScreen::on_char(uint32_t ch)
{
_owner.on_char(ch);
}
void RedScreen::on_deactivate()
{
relase_mouse();

View File

@ -138,6 +138,7 @@ private:
virtual void on_key_press(RedKey key);
virtual void on_key_release(RedKey key);
virtual void on_char(uint32_t ch);
virtual void on_deactivate();
virtual void on_activate();

View File

@ -94,6 +94,46 @@ static inline void send_filtered_keys(RedWindow* window)
filtered_up_keys.clear();
}
static inline bool is_high_surrogate(uint32_t val)
{
return val >= 0xd800 && val <= 0xdbff;
}
static inline bool is_low_surrogate(uint32_t val)
{
return val >= 0xdc00 && val <= 0xdfff;
}
static uint32_t utf16_to_utf32(uint16_t*& utf16, int& len)
{
if (!len) {
return 0;
}
uint32_t val = utf16[0];
if (!is_high_surrogate(val)) {
utf16++;
len--;
return val;
}
if (len < 2) {
THROW("partial char");
}
uint32_t val2 = utf16[1];
if (!is_low_surrogate(val2)) {
THROW("invalid sequence");
}
utf16 += 2;
len -= 2;
return (((val & 0x3ff) << 10) | (val2 & 0x3ff)) + 0x10000;
}
LRESULT CALLBACK RedWindow_p::WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
RedWindow* window = (RedWindow*)GetWindowLong(hWnd, GWL_USERDATA);
@ -177,6 +217,19 @@ LRESULT CALLBACK RedWindow_p::WindowProc(HWND hWnd, UINT message, WPARAM wParam,
case WM_KEYDOWN: {
RedKey key = translate_key(wParam, HIWORD(lParam) & 0xff, (lParam & (1 << 24)) != 0);
window->get_listener().on_key_press(key);
BYTE key_state[256];
WCHAR buff[10];
uint16_t* str_buf = (uint16_t*)buff;
GetKeyboardState(key_state);
int n = ToUnicode(wParam, HIWORD(lParam) & 0xff, key_state, buff, 10, 0);
if (n > 0) {
uint32_t utf32;
while ((utf32 = utf16_to_utf32(str_buf, n)) != 0) {
window->get_listener().on_char(utf32);
}
}
// Allow Windows to translate Alt-F4 to WM_CLOSE message.
if (!window->_key_interception_on) {
return DefWindowProc(hWnd, message, wParam, lParam);

View File

@ -64,7 +64,9 @@
static Display* x_display = NULL;
static XVisualInfo **vinfo = NULL;
static GLXFBConfig **fb_config;
static GLXFBConfig **fb_config = NULL;
static XIM x_input_method = NULL;
static XIC x_input_context = NULL;
static XContext win_proc_context;
static ProcessLoop* main_loop = NULL;
@ -193,6 +195,11 @@ GLXFBConfig** XPlatform::get_fbconfig()
return fb_config;
}
XIC XPlatform::get_input_context()
{
return x_input_context;
}
void XPlatform::set_win_proc(Window win, win_proc_t proc)
{
if (XSaveContext(x_display, win, win_proc_context, (XPointer)proc)) {
@ -2021,6 +2028,25 @@ static void init_kbd()
num_lock_mask = get_modifier_mask(XK_Num_Lock);
}
static void init_XIM()
{
char app_name[20];
strcpy(app_name, "spicec");
XSetLocaleModifiers("");
x_input_method = XOpenIM(x_display, NULL, app_name, app_name);
if (!x_input_method) {
THROW("open IM failed");
}
x_input_context = XCreateIC(x_input_method, XNInputStyle, XIMPreeditNone | XIMStatusNone, NULL);
if (!x_input_context) {
THROW("create IC failed");
}
}
static int x_error_handler(Display* display, XErrorEvent* error_event)
{
char error_str[256];
@ -2072,6 +2098,8 @@ void Platform::init()
DBG(0, "");
setlocale(LC_ALL, "");
threads_enable = XInitThreads();
@ -2127,6 +2155,7 @@ void Platform::init()
init_kbd();
init_xrandr();
init_xrender();
init_XIM();
struct sigaction act;
memset(&act, 0, sizeof(act));

View File

@ -54,6 +54,7 @@
static Display* x_display = NULL;
static XContext user_data_context;
static bool using_evdev = false;
static XIC x_input_context = NULL;
static Atom wm_protocol_atom;
static Atom wm_delete_window_atom;
@ -711,6 +712,49 @@ static inline RedButton to_red_button(unsigned int botton, unsigned int& state,
return ret;
}
void RedWindow_p::handle_key_press_event(RedWindow& window, XKeyEvent* event)
{
static int buf_size = 0;
static char* utf8_buf = NULL;
static wchar_t* utf32_buf = NULL;
KeySym key_sym;
Status status;
int len;
window.get_listener().on_key_press(to_red_key_code(event->keycode));
for (;;) {
len = XwcLookupString(x_input_context, event, utf32_buf, buf_size, &key_sym, &status);
if (status != XBufferOverflow) {
break;
}
free(utf32_buf);
free(utf32_buf);
utf8_buf = new char[len];
utf32_buf = new wchar_t[len];
buf_size = len;
}
switch (status) {
case XLookupChars:
case XLookupBoth: {
uint32_t* now = (uint32_t*)utf32_buf;
uint32_t* end = now + len;
for (; now < end; now++) {
window.get_listener().on_char(*now);
}
break;
}
case XLookupNone:
case XLookupKeySym:
break;
default:
THROW("unexpected status %d", status);
}
}
void RedWindow_p::win_proc(XEvent& event)
{
XPointer window_pointer;
@ -733,7 +777,7 @@ void RedWindow_p::win_proc(XEvent& event)
break;
}
case KeyPress:
red_window->get_listener().on_key_press(to_red_key_code(event.xkey.keycode));
red_window->handle_key_press_event(*red_window, &event.xkey);
break;
case KeyRelease: {
RedKey key = to_red_key_code(event.xkey.keycode);
@ -1925,6 +1969,7 @@ void RedWindow::on_focus_in()
return;
}
_focused = true;
XwcResetIC(x_input_context);
XPlatform::on_focus_in();
get_listener().on_activate();
if (_trace_key_interception && _pointer_in_window) {
@ -1976,6 +2021,7 @@ void RedWindow::set_menu(Menu* menu)
void RedWindow::init()
{
x_display = XPlatform::get_display();
x_input_context = XPlatform::get_input_context();
ASSERT(x_display);
user_data_context = XUniqueContext();

View File

@ -50,6 +50,7 @@ public:
static Cursor create_invisible_cursor(Window window);
void set_glx(int width, int height);
static void handle_key_press_event(RedWindow& red_window, XKeyEvent* event);
protected:
int _screen;

View File

@ -23,6 +23,7 @@ public:
static Display* get_display();
static XVisualInfo** get_vinfo();
static GLXFBConfig** get_fbconfig();
static XIC get_input_context();
typedef void (*win_proc_t)(XEvent& event);
static void set_win_proc(Window win, win_proc_t proc);