void Ctrl::EventProc(XWindow& w, XEvent *event) { GuiLock __; eventid++; Ptr<Ctrl> _this = this; bool pressed = false; int count = 1; switch(event->type) { case NoExpose: LLOG("NoExpose serial " << event->xnoexpose.serial); break; case GraphicsExpose: LLOG("GraphicsExpose serial " << event->xgraphicsexpose.serial); case Expose: { XExposeEvent& e = event->xexpose; w.exposed = true; LLOG("Expose " << RectC(e.x, e.y, e.width, e.height)); Invalidate(w, RectC(e.x, e.y, e.width, e.height)); } return; case ConfigureNotify: { XConfigureEvent& e = event->xconfigure; int x, y; Window dummy; // 01/12/2007 - mdelfede // added support for windowed controls // if(top) // XTranslateCoordinates(Xdisplay, top->window, Xroot, 0, 0, &x, &y, &dummy); if(top) { Window DestW = (parent ? GetParentWindow() : Xroot); XTranslateCoordinates(Xdisplay, top->window, DestW, 0, 0, &x, &y, &dummy); Rect rect = RectC(x, y, e.width, e.height); LLOG("CongigureNotify " << rect); if(GetRect() != rect) SetWndRect(rect); // Synchronizes native windows (NOT the main one) } SyncNativeWindows(); // 01/12/2007 - END } return; default: if(!IsEnabled()) return; } LTIMING("XUserInput"); switch(event->type) { case FocusIn: if(w.xic) XSetICFocus(w.xic); break; case FocusOut: if(w.xic) XUnsetICFocus(w.xic); break; case KeyPress: pressed = true; LLOG("event type:" << event->type << " state:" << event->xkey.state << "keycode:" << event->xkey.keycode); for(;;) { XEvent ev1[1], ev2[1]; bool hasev2 = false; if(!IsWaitingEvent()) break; do XNextEvent(Xdisplay, ev1); while(ev1->type == NoExpose && IsWaitingEvent()); LLOG("ev1 type:" << ev1->type << " state:" << ev1->xkey.state << "keycode:" << ev1->xkey.keycode); if(ev1->type == KeyPress) *ev2 = *ev1; else { if(ev1->type != KeyRelease || ev1->xkey.state != event->xkey.state || ev1->xkey.keycode != event->xkey.keycode || !IsWaitingEvent()) { XPutBackEvent(Xdisplay, ev1); break; } do XNextEvent(Xdisplay, ev2); while(ev2->type == NoExpose && IsWaitingEvent()); LLOG("ev2 type:" << ev2->type << " state:" << ev2->xkey.state << "keycode:" << ev2->xkey.keycode); hasev2 = true; } if(ev2->type != KeyPress || ev2->xkey.state != event->xkey.state || ev2->xkey.keycode != event->xkey.keycode) { if(hasev2) XPutBackEvent(Xdisplay, ev2); XPutBackEvent(Xdisplay, ev1); break; } else { XFilterEvent(ev1, None); if(hasev2) XFilterEvent(ev2, None); } count++; } case KeyRelease: { mousePos = Point(event->xkey.x_root, event->xkey.y_root); char buff[128]; Xeventtime = event->xkey.time; LLOG("Key Xeventtime: " << Xeventtime << " count:" << count); KeySym keysym; int chr = 0; WString wtext; if(pressed && w.xic) { Status status; int len = Xutf8LookupString(w.xic, &event->xkey, buff, sizeof(buff), &keysym, &status); buff[len] = 0; if(status == XLookupChars || status == XLookupBoth) { chr = FromUtf8(buff, len)[0]; if(status == XLookupChars) wtext = FromUtf8(buff, len); } else if(status != XLookupKeySym && status != XLookupBoth) keysym = 0; } else { int len = XLookupString(&event->xkey, buff, sizeof(buff), &keysym, NULL); buff[len] = 0; chr = FromUtf8(buff, len)[0]; if(len > 1) wtext = FromUtf8(buff, len); } if(keysym == XK_Control_L || keysym == XK_Control_R) { keysym = XK_Control_L; if(pressed) sKbdState |= ControlMask; else sKbdState &= ~ControlMask; } if(keysym == XK_Shift_L || keysym == XK_Shift_R) { keysym = XK_Shift_L; if(pressed) sKbdState |= ShiftMask; else sKbdState &= ~ShiftMask; } if(keysym == XK_Meta_L || keysym == XK_Meta_R || keysym == XK_Alt_L || keysym == XK_Alt_R || keysym == XK_Super_L || keysym == XK_Super_R || keysym == XK_Hyper_L || keysym == XK_Hyper_R || keysym == XK_ISO_Prev_Group) { keysym = XK_Meta_L; if(pressed) sKbdState |= Mod1Mask; else sKbdState &= ~Mod1Mask; } LLOG("KeySym:" << FormatIntHex(keysym) << " " << (char)keysym << " " << count); dword up = pressed ? 0 : K_KEYUP; static struct { KeySym keysym; dword key; } tab[] = { { XK_ISO_Left_Tab, K_TAB|K_SHIFT }, { XK_BackSpace, K_BACKSPACE }, { XK_Tab, K_TAB }, { XK_Return, K_ENTER }, { XK_KP_Enter, K_ENTER }, { XK_Escape, K_ESCAPE }, { XK_space, K_SPACE }, { XK_KP_Space, K_SPACE }, { XK_KP_Tab, K_TAB }, { XK_KP_Enter, K_ENTER }, { XK_KP_F1, K_F1 }, { XK_KP_F2, K_F2 }, { XK_KP_F3, K_F3 }, { XK_KP_F4, K_F4 }, { XK_KP_Home, K_HOME }, { XK_KP_Left, K_LEFT }, { XK_KP_Up, K_UP }, { XK_KP_Right, K_RIGHT }, { XK_KP_Down, K_DOWN }, { XK_KP_Page_Up, K_PAGEUP }, { XK_KP_Page_Down, K_PAGEDOWN }, { XK_KP_End, K_END }, { XK_KP_Begin, K_HOME }, { XK_KP_Insert, K_INSERT }, { XK_KP_Delete, K_DELETE }, }; for(int i = 0; i < __countof(tab); i++) if(tab[i].keysym == keysym) { DispatchKey(KEYtoK(tab[i].key)|up, count); return; } if(GetShift() && chr == 0) { static dword k[] = { 41, 33, 64, 35, 36, 37, 94, 38, 42, 40 }; for(int i = 0; i < 10; i++) if(keysym == k[i]) { DispatchKey(KEYtoK(i + K_0)|up, count); return; } } if(keysym >= 48 && keysym <= 57 && chr == 0) { DispatchKey(KEYtoK(keysym - 48 + K_0)|up, count); return; } if(chr >= 1 && chr < 32) { DispatchKey(KEYtoK(chr - 1 + K_CTRL_A)|up, count); return; } if(keysym >= 0xff80 && keysym <= 0xffb9 && chr) { DispatchKey(KEYtoK(chr)|up, count); return; } if(keysym >= 0xff00 && chr < 128 || (GetCtrl() || GetAlt()) && keysym >= 0x20 && keysym < 0x7f) { if(keysym >= 'a' && keysym <= 'z') keysym = keysym - 'a' + 'A'; DispatchKey(KEYtoK(keysym|K_DELTA)|up, count); return; } if((chr == 32 || chr == 9 || chr == 13) && !pressed) DispatchKey(chr|K_KEYUP, count); if(chr && pressed) { DispatchKey(chr, count); for(int ii = 1; ii < wtext.GetLength(); ii++) DispatchKey(wtext[ii], count); } } break; case ButtonPress: { if(!HasWndFocus() && !popup) SetWndFocus(); ClickActivateWnd(); mousePos = Point(event->xbutton.x_root, event->xbutton.y_root); ReleaseGrab(); XButtonEvent& e = event->xbutton; sModState = e.state; Xeventtime = e.time; if(ignoreclick) break; Point p = Point(e.x, e.y); dword action = DOWN; if((dword)e.time - (dword)Xbuttontime < 800) { action = DOUBLE; Xbuttontime = Xeventtime - 0x80000000; } else { Xbuttontime = e.time; Xbuttonpos = mousePos; } switch(e.button) { case Button1: sModState |= Button1Mask; DispatchMouse(LEFT|action, p, 0); break; case Button2: sModState |= Button2Mask; if(Xbuttons < 3) DispatchMouse(RIGHT|action, p, 0); else DispatchMouse(MIDDLE|action, p, 0); break; case Button3: sModState |= Button3Mask; DispatchMouse(RIGHT|action, p, 0); break; } if(_this) PostInput(); } break; case ButtonRelease: { mousePos = Point(event->xbutton.x_root, event->xbutton.y_root); XButtonEvent& e = event->xbutton; sModState = e.state; Xeventtime = e.time; Point p = Point(e.x, e.y); switch(e.button) { case Button1: sModState &= ~Button1Mask; break; case Button2: sModState &= ~Button2Mask; break; case Button3: sModState &= ~Button3Mask; break; } if(ignoreclick) EndIgnore(); else switch(e.button) { case Button1: DispatchMouse(LEFTUP, p, 0); break; case Button2: if(Xbuttons < 3) DispatchMouse(RIGHTUP, p, 0); else DispatchMouse(MIDDLEUP, p, 0); break; case Button3: DispatchMouse(RIGHTUP, p, 0); break; case Button4: DispatchMouse(MOUSEWHEEL, p, 120); break; case Button5: DispatchMouse(MOUSEWHEEL, p, -120); break; } if(_this) PostInput(); } break; case MotionNotify: while(XCheckWindowEvent(Xdisplay, top->window, PointerMotionMask, event)); EndIgnore(); mousePos = Point(event->xmotion.x_root, event->xmotion.y_root); Xeventtime = event->xmotion.time; Point p = mousePos - Xbuttonpos; if(max(abs(p.x), abs(p.y)) > 4) Xbuttontime = Xeventtime - 0x80000000; sModState = event->xmotion.state; DispatchMouse(MOUSEMOVE, Point(event->xmotion.x, event->xmotion.y)); DoCursorShape(); break; } DropEvent(w, event); }
void Ctrl::Proc() { #ifdef LOG_EVENTS String ev = "?"; Tuple2<int, const char *> *f = FindTuple(xEvent, __countof(xEvent), CurrentEvent.type); if(f) ev = f->b; LOG(rmsecs() << " PROCESS EVENT " << Upp::Name(this) << " " << ev); ProcStop tm; tm.ev = ev; #endif if(!IsOpen()) return; Ptr<Ctrl> _this = this; bool pressed = false; int kv; static int clicktime = msecs() - 100000; switch(CurrentEvent.type) { case GDK_MOTION_NOTIFY: { GtkMouseEvent(MOUSEMOVE, MOUSEMOVE, 0); break; } case GDK_BUTTON_PRESS: if(!HasWndFocus() && !popup) SetWndFocus(); ClickActivateWnd(); if(ignoremouseup) { KillRepeat(); ignoreclick = false; ignoremouseup = false; } if(!ignoreclick) GtkButtonEvent(msecs(clicktime) < 250 ? DOUBLE : DOWN); clicktime = msecs(); break; /* case GDK_2BUTTON_PRESS: if(!ignoreclick) GtkButtonEvent(DOUBLE); break; */ case GDK_BUTTON_RELEASE: if(ignoreclick) EndIgnore(); else GtkButtonEvent(UP); break; case GDK_SCROLL: { GtkMouseEvent(MOUSEWHEEL, MOUSEWHEEL, CurrentEvent.value); break; } case GDK_KEY_PRESS: pressed = true; case GDK_KEY_RELEASE: kv = CurrentEvent.value; if(kv >= 0 && kv < 65536) { LLOG("keyval " << FormatIntHex(kv) << ' ' << (char)kv); if(kv >= 'a' && kv <= 'z') kv = kv - 'a' + 'A'; static Tuple2<int, int> cv[] = { { GDKEY(BackSpace), K_BACKSPACE }, { GDKEY(Tab), K_TAB }, { GDKEY(ISO_Left_Tab), K_TAB }, { GDKEY(Return), K_ENTER }, { GDKEY(Escape), K_ESCAPE }, { GDKEY(space), K_SPACE }, { GDKEY(Control_L), K_CTRL_KEY }, { GDKEY(Control_R), K_CTRL_KEY }, { GDKEY(Shift_L), K_SHIFT_KEY }, { GDKEY(Shift_R), K_SHIFT_KEY }, { GDKEY(Alt_L), K_ALT_KEY }, { GDKEY(Alt_R), K_ALT_KEY }, { GDKEY(KP_Space), K_SPACE }, { GDKEY(KP_Tab), K_TAB }, { GDKEY(KP_Enter), K_ENTER }, { GDKEY(KP_F1), K_F1 }, { GDKEY(KP_F2), K_F2 }, { GDKEY(KP_F3), K_F3 }, { GDKEY(KP_F4), K_F4 }, { GDKEY(KP_Home), K_HOME }, { GDKEY(KP_Left), K_LEFT }, { GDKEY(KP_Up), K_UP }, { GDKEY(KP_Right), K_RIGHT }, { GDKEY(KP_Down), K_DOWN }, { GDKEY(KP_Page_Up), K_PAGEUP }, { GDKEY(KP_Page_Down), K_PAGEDOWN }, { GDKEY(KP_End), K_END }, { GDKEY(KP_Begin), K_HOME }, { GDKEY(KP_Insert), K_INSERT }, { GDKEY(KP_Delete), K_DELETE }, }; Tuple2<int, int> *x = FindTuple(cv, __countof(cv), kv); if(x) kv = x->b; else kv += K_DELTA; if(GetShift() && kv != K_SHIFT_KEY) kv |= K_SHIFT; if(GetCtrl() && kv != K_CTRL_KEY) kv |= K_CTRL; if(GetAlt() && kv != K_ALT_KEY) kv |= K_ALT; LLOG(GetKeyDesc(kv) << ", pressed: " << pressed << ", count: " << CurrentEvent.count); #ifdef GDK_WINDOWING_X11 if(pressed) for(int i = 0; i < hotkey.GetCount(); i++) { if(hotkey[i] && keyhot[i] == (dword)kv) { hotkey[i](); return; } } #endif DispatchKey(!pressed * K_KEYUP + kv, CurrentEvent.count); } break; case EVENT_TEXT: { WString h = CurrentEvent.value; for(int i = 0; i < h.GetCount(); i++) // TODO: Add compression DispatchKey(h[i], 1); break; } case GDK_DELETE: { TopWindow *w = dynamic_cast<TopWindow *>(this); if(w) { if(IsEnabled()) { IgnoreMouseUp(); w->WhenClose(); } } return; } case GDK_CONFIGURE: { Rect rect = CurrentEvent.value; if(GetRect() != rect) SetWndRect(rect); } break; default: return; } if(_this) _this->PostInput(); }