mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice
synced 2025-12-26 14:41:25 +00:00
client: KeyHandler now receive unicode char event in addition to RedKey events
This commit is contained in:
parent
81241dd825
commit
6c5966d8ed
@ -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)
|
||||
{
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user