void FramebufferBackend::openFrameBuffer() { VirtualTerminal::self()->init(); int fd = LogindIntegration::self()->takeDevice(deviceIdentifier().constData()); if (fd < 0) { qCWarning(KWIN_FB) << "Failed to open frame buffer device through logind, trying without"; } fd = open(deviceIdentifier().constData(), O_RDWR | O_CLOEXEC); if (fd < 0) { qCWarning(KWIN_FB) << "failed to open frame buffer device"; return; } m_fd = fd; queryScreenInfo(); setReady(true); emit screensQueried(); }
void X11WindowedBackend::init() { int screen = 0; xcb_connection_t *c = nullptr; Display *xDisplay = XOpenDisplay(deviceIdentifier().constData()); if (xDisplay) { c = XGetXCBConnection(xDisplay); XSetEventQueueOwner(xDisplay, XCBOwnsEventQueue); screen = XDefaultScreen(xDisplay); } if (c && !xcb_connection_has_error(c)) { m_connection = c; m_screenNumber = screen; m_display = xDisplay; for (xcb_screen_iterator_t it = xcb_setup_roots_iterator(xcb_get_setup(m_connection)); it.rem; --screen, xcb_screen_next(&it)) { if (screen == m_screenNumber) { m_screen = it.data; } } XRenderUtils::init(m_connection, m_screen->root); createWindow(); startEventReading(); connect(this, &X11WindowedBackend::cursorChanged, this, [this] { createCursor(softwareCursor(), softwareCursorHotspot()); } ); setReady(true); waylandServer()->seat()->setHasPointer(true); waylandServer()->seat()->setHasKeyboard(true); emit screensQueried(); } else { emit initFailed(); } }
bool SimultaneousKeyPresses::remap(void) { if (! EventInputQueue::queue_) return false; // We consider "Shift_L+Shift_R to Space". // When we press keys by the following order. // // (1) Shift_L Down // (2) Shift_R Down // (3) Shift_L Up // (4) Shift_R Up // // First remap(): // (1) Shift_L Down -> to virtualkey_ // (2) Shift_R Down -> removed // (3) Shift_L Up -> no change // (4) Shift_R Up -> no change // // Second remap(): // (3) Shift_L Up -> removed // (4) Shift_R Up -> no change // However, we need to remove (4) at the same time. // If (4) is alive, Shift_R Up event which we don't intend is fired in EventInputQueue. // So, we retry handling KeyUp event once more when we drop KeyUp event. EventInputQueue::Item* front = static_cast<EventInputQueue::Item*>(EventInputQueue::queue_->front()); if (! front) return false; // backup device information. DeviceIdentifier deviceIdentifier(front->deviceIdentifier); // ------------------------------------------------------------ // fire KeyUp event if needed. for (size_t i = 0; i < fromInfo_.size(); ++i) { if (! fromInfo_[i].isActive()) continue; if (! fromInfo_[i].isTargetKeyUp(*front)) continue; // -------------------- EventInputQueue::queue_->pop_front(); fromInfo_[i].deactivate(); // -------------------- // if all keys are released, fire KeyUp event. bool isAllDeactived = true; for (size_t j = 0; j < fromInfo_.size(); ++j) { if (fromInfo_[j].isActive()) { isAllDeactived = false; } } if (isAllDeactived) { push_remapped(false, deviceIdentifier); } return true; } // ------------------------------------------------------------ // handle KeyDown event. if (! FlagStatus::makeFlags().isOn(fromFlags_)) return false; // -------------------- // scan items in queue_. while (downKeys_.size() < fromInfo_.size()) { downKeys_.push_back(NULL); } // Then, downKeys_.size() >= fromInfo_.size() for (size_t i = 0; i < fromInfo_.size(); ++i) { downKeys_[i].item = NULL; } for (;;) { // We consider "Shift_L+Shift_R to Space". // When we press keys by the following order. // // (1) Shift_L Down // (2) Shift_L Up // (3) Shift_R Down // (4) Shift_R Up // // If fromKey was released before all keys are pressed, // we must not handle these keys as SimultaneousKeyPresses. // for (size_t i = 0; i < fromInfo_.size(); ++i) { if (fromInfo_[i].isTargetKeyDown(*front)) { downKeys_[i].item = front; break; } else if (fromInfo_[i].isTargetKeyUp(*front)) { return false; } } // ---------------------------------------- bool isAllKeysDown = true; for (size_t i = 0; i < fromInfo_.size(); ++i) { if (! downKeys_[i].item) { isAllKeysDown = false; } else { // Checking strict key order. // // If isStrictKeyOrder_ == true, // we must not handle the following state as SimultaneousKeyPresses. // // - downKeys_[0] == NULL // - downKeys_[1] != NULL // if (! isAllKeysDown && isStrictKeyOrder_) { return false; } } } if (isAllKeysDown) { for (size_t i = 0; i < fromInfo_.size(); ++i) { fromInfo_[i].activate(); EventInputQueue::queue_->erase(downKeys_[i].item); } push_remapped(true, deviceIdentifier); return true; } // ---------------------------------------- front = static_cast<EventInputQueue::Item*>(front->getnext()); if (! front) return false; } return false; }
RemapSimultaneousKeyPressesResult::Value SimultaneousKeyPresses::remapSimultaneousKeyPresses(void) { // We consider "Shift_L+Shift_R to Space". // When we press keys by the following order. // // (1) Shift_L Down // (2) Shift_R Down // (3) Shift_L Up // (4) Shift_R Up // // First remap(): // (1) Shift_L Down -> to virtualkey_ // (2) Shift_R Down -> removed // (3) Shift_L Up -> no change // (4) Shift_R Up -> no change // // Second remap(): // (3) Shift_L Up -> removed // (4) Shift_R Up -> no change // However, we need to remove (4) at the same time. // If (4) is alive, Shift_R Up event which we don't intend is fired in EventInputQueue. // So, we retry handling KeyUp event once more when we drop KeyUp event. auto front = static_cast<EventInputQueue::Item*>(EventInputQueue::queue_.safe_front()); if (!front) { return RemapSimultaneousKeyPressesResult::NOT_CHANGED; } if (!(front->isSimultaneousKeyPressesTarget)) { return RemapSimultaneousKeyPressesResult::NOT_CHANGED; } // backup device information. DeviceIdentifier deviceIdentifier(front->deviceIdentifier); ListHookedDevice::WeakPointer_Item device(front->deviceWeakPointer); // ------------------------------------------------------------ // fire KeyUp event if needed. for (size_t i = 0; i < fromInfo_.size(); ++i) { if (!fromInfo_[i].isActive(device)) continue; if (!fromInfo_[i].fromEvent().isTargetUpEvent(front->getParamsBase())) continue; // -------------------- if (isPostFromEventsAsRaw_) { front->isSimultaneousKeyPressesTarget = false; } else { EventInputQueue::queue_.pop_front(); } fromInfo_[i].deactivate(device); // -------------------- // if all keys are released, fire KeyUp event. bool isAllDeactived = true; for (size_t j = 0; j < fromInfo_.size(); ++j) { if (fromInfo_[j].isActive(device)) { isAllDeactived = false; } } if (!isAllDeactived) { return RemapSimultaneousKeyPressesResult::QUEUE_CHANGED; } push_remapped(false, deviceIdentifier, device); return RemapSimultaneousKeyPressesResult::APPLIED; } // ------------------------------------------------------------ // handle KeyDown event. if (!FlagStatus::globalFlagStatus().isOn(fromModifierFlags_)) return RemapSimultaneousKeyPressesResult::NOT_CHANGED; // Check the first item in queue_ is target. // // We need to skip when the first item is not target. // In this case: // - shift+[a+s] to space // - [a+s] to return // When queue_ is [shift, a, s], we need to change these events to space. // If we do not check the first item is target, // [shift, a, s] will be changed to [shift, return]. // It's not intended. for (size_t i = 0; i < fromInfo_.size(); ++i) { if (fromInfo_[i].fromEvent().isTargetDownEvent(front->getParamsBase())) { goto scan; } } // skip return RemapSimultaneousKeyPressesResult::NOT_CHANGED; scan: // -------------------- // scan items in queue_. while (downKeys_.size() < fromInfo_.size()) { downKeys_.push_back(nullptr); } // Then, downKeys_.size() >= fromInfo_.size() for (size_t i = 0; i < fromInfo_.size(); ++i) { downKeys_[i].item = nullptr; } for (;;) { // We consider "Shift_L+Shift_R to Space". // When we press keys by the following order. // // (1) Shift_L Down // (2) Shift_L Up // (3) Shift_R Down // (4) Shift_R Up // // If fromKey was released before all keys are pressed, // we must not handle these keys as SimultaneousKeyPresses. // for (size_t i = 0; i < fromInfo_.size(); ++i) { if (fromInfo_[i].fromEvent().isTargetDownEvent(front->getParamsBase())) { downKeys_[i].item = front; break; } else if (fromInfo_[i].fromEvent().isTargetUpEvent(front->getParamsBase())) { return RemapSimultaneousKeyPressesResult::NOT_CHANGED; } } // ---------------------------------------- bool isAllKeysDown = true; for (size_t i = 0; i < fromInfo_.size(); ++i) { if (!downKeys_[i].item) { isAllKeysDown = false; } else { // Checking strict key order. // // If isStrictKeyOrder_ == true, // we must not handle the following state as SimultaneousKeyPresses. // // - downKeys_[0] == nullptr // - downKeys_[1] != nullptr // if (!isAllKeysDown && isStrictKeyOrder_) { return RemapSimultaneousKeyPressesResult::NOT_CHANGED; } } } if (isAllKeysDown) { // We use the reverse iterator for isPostFromEventsAsRaw_. for (int i = static_cast<int>(fromInfo_.size()) - 1; i >= 0; --i) { fromInfo_[i].activate(device); if (!downKeys_[i].item) continue; if (isPostFromEventsAsRaw_) { bool retainFlagStatusTemporaryCount = false; bool push_back = false; bool isSimultaneousKeyPressesTarget = false; EventInputQueue::enqueue_((downKeys_[i].item)->getParamsBase(), retainFlagStatusTemporaryCount, deviceIdentifier, device, push_back, isSimultaneousKeyPressesTarget); } EventInputQueue::queue_.erase_and_delete(downKeys_[i].item); } push_remapped(true, deviceIdentifier, device); return RemapSimultaneousKeyPressesResult::APPLIED; } // ---------------------------------------- // get next target item. for (;;) { front = static_cast<EventInputQueue::Item*>(front->getnext()); if (!front) { return RemapSimultaneousKeyPressesResult::NOT_CHANGED; } if (front->isSimultaneousKeyPressesTarget) { break; } } } return RemapSimultaneousKeyPressesResult::NOT_CHANGED; }
bool AMGenericLinuxJoystick::attemptConnection() { // Do we have a connection open already? Close the reading thread, and close the file descriptor. if(readThread_) { disconnect(readThread_, SIGNAL(finished()), this, SLOT(onReadThreadFinished())); readThread_->stop(); readThread_->wait(); delete readThread_; readThread_ = 0; close(fd_); fd_ = -1; AMErrorMon::information(this, 0, QString("Disconnected from joystick: '%1' before attempting to reconnect on '%2'").arg(deviceDescription()).arg(deviceIdentifier())); emit connected(false); } // Try opening the joystick device fd_ = open(deviceIdentifier_.toAscii().constData(), O_RDONLY | O_NONBLOCK); if(fd_ == -1) { // Failed to open. Maybe not plugged in yet? Just keep trying. We'll re-attempt in 2 seconds. QTimer::singleShot(2000, this, SLOT(attemptConnection())); return false; } // Get the number of buttons and number of axes, using special ioctl() on the file descriptor. char numAxes; ioctl(fd_, JSIOCGAXES, &numAxes); axisCount_ = numAxes; axisPositions_.resize(axisCount_); char numButtons; ioctl(fd_, JSIOCGBUTTONS, &numButtons); buttonCount_ = numButtons; buttonStates_.resize(buttonCount_); // Get the joystick description char description[256]; if(ioctl(fd_, JSIOCGNAME(sizeof(description)), description) < 0) deviceDescription_ = "Unknown"; else deviceDescription_ = QString(description); // Finally, start up the thread for reading from the joystick. readThread_ = new AMGenericLinuxJoystickThread(fd_, this); connect(readThread_, SIGNAL(finished()), this, SLOT(onReadThreadFinished())); connect(readThread_, SIGNAL(joystickEvents(QVector<AMGenericLinuxJoystickEvent>)), this, SLOT(onJoystickEvents(QVector<AMGenericLinuxJoystickEvent>))); readThread_->start(); AMErrorMon::information(this, 0, QString("Connected to joystick: '%1' on '%2'.").arg(deviceDescription()).arg(deviceIdentifier())); emit connected(true); return true; }