Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
**/*.qmd-pure
/applications_root/
/testing_extensions/
/.vscode
/shim/build
/xovi/*
!/xovi/template
!/xovi/make.sh
.qmake.stash
appload
Makefile
1 change: 1 addition & 0 deletions resources/qml/appload.qml
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ Rectangle {

win.appName = modelData.name;
win.supportsScaling = modelData.supportsScaling;
win.supportsVirtualKeyboard = modelData.supportsVirtualKeyboard;
win.disablesWindowedMode = modelData.disablesWindowedMode;

win.globalWidth = Qt.binding(function() { return _appLoadView.width; })
Expand Down
64 changes: 64 additions & 0 deletions resources/qml/window.qml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ FocusScope {

property alias appName: _appName.text
property bool supportsScaling: false
property bool supportsVirtualKeyboard: false
property var qtfbKey: -1
property int appPid: -1
property bool minimized: false
Expand Down Expand Up @@ -288,6 +289,69 @@ FocusScope {
}
}

Rectangle {
id: virtualKeyboardButton
width: parent.height
height: parent.height
anchors.left: parent.left
border.width: 2
border.color: "black"
color: parent.color
visible: supportsVirtualKeyboard

TextArea {
anchors.fill: parent
color: "white"
text: " "

function sendVirtualKeyCode(code) {
windowCanvas.virtualKeyboardKeyDown(code);

// Hold each key press for 100 milliseconds
(function(c) {
var t = Qt.createQmlObject('import QtQuick 2.5; Timer { interval: 100; repeat: false }', virtualKeyboardButton);

t.triggered.connect(function() {
windowCanvas.virtualKeyboardKeyUp(c);

t.destroy();
});

t.start();
})(code);
}

onFocusChanged: {
if (focus) {
cursorPosition = 1;
sendVirtualKeyCode(0xf001) // Arbitrary unused keycode
} else {
sendVirtualKeyCode(0xf000)
}
}

onTextChanged: {
if (text.length == 0) { // Backspace pressed
sendVirtualKeyCode(8)
} else if (text.indexOf('\n') != -1) { // Enter pressed
sendVirtualKeyCode(13)
} else if (text.length == 2) { // Regular key pressed
var lastChar = text.charAt(text.length - 1)

if (text[0] != ' ') {
lastChar = text[0]
}

sendVirtualKeyCode(lastChar.charCodeAt(0))
}

text = " ";

cursorPosition = 1;
}
}
}

Rectangle {
width: parent.width
height: 2
Expand Down
93 changes: 91 additions & 2 deletions shim/src/input-shim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <dlfcn.h>
#include <poll.h>
#include <algorithm>
#include <tuple>

#include "qtfb-client/qtfb-client.h"

Expand Down Expand Up @@ -54,7 +55,7 @@

extern qtfb::ClientConnection *clientConnection;
extern int shimInputType;
extern std::set<fileident_t> *identDigitizer, *identTouchScreen, *identButtons, *identNull;
extern std::set<fileident_t> *identDigitizer, *identTouchScreen, *identButtons, *identVirtualKeyboard, *identNull;

struct TouchSlotState {
int x, y;
Expand All @@ -65,7 +66,8 @@ std::map<int, TouchSlotState> touchStates;
#define QUEUE_TOUCH 1
#define QUEUE_PEN 2
#define QUEUE_BUTTONS 3
#define QUEUE_NULL 4
#define QUEUE_VIRTUALKEYBOARD 4
#define QUEUE_NULL 5

struct PIDEventQueue *pidEventQueue;

Expand Down Expand Up @@ -98,6 +100,50 @@ static int mapKey(int x) {
return 0;
}

const bool isShifted(int ascii) {
if (ascii >= '!' && ascii <= '&') return true;
if (ascii >= '(' && ascii <= '+') return true;
if (ascii >= ':' && ascii <= ':') return true;
if (ascii >= '<' && ascii <= '<') return true;
if (ascii >= '>' && ascii <= 'Z') return true;
if (ascii >= '^' && ascii <= '_') return true;
if (ascii >= '{' && ascii <= '~') return true;

if (ascii >= 0xA2 && ascii <= 0xA3) return true; // ¢ to £
if (ascii >= 0xA6 && ascii <= 0xA8) return true; // ¦ to ¨
if (ascii >= 0xAF && ascii <= 0xB0) return true; // ¯ to °
if (ascii >= 0xB9 && ascii <= 0xB0) return true; // ¹ to °
if (ascii >= 0xC0 && ascii <= 0xD6) return true; // À to Ö
if (ascii >= 0xD8 && ascii <= 0xDE) return true; // Ø to Þ

return false;
}

std::tuple<int, bool> mapAsciiToX11Key(int ascii) {
const bool shifted = isShifted(ascii);

// All ASCII printable characters
if (ascii >= ' ' && ascii <= '~') {
return {ascii, shifted};
}

// All ASCII printable extended characters
if (ascii >= 0x00a0 && ascii <= 0x00ff) {
return {ascii, shifted};
}

// ASCII unprintable characters
switch (ascii) {
case 8: return {0xff08, false}; // Backspace
case 9: return {0xff09, false}; // Tab
case 13: return {0xff0d, false}; // Enter/Return
case 27: return {0xff1b, false}; // Escape
case 127: return {0xffff, false}; // Delete
}

return {0x0000, false};
}

static void pushToAll(int queueType, struct input_event evt) {
struct PIDEventQueue *current = pidEventQueue;
while(current != NULL) {
Expand Down Expand Up @@ -217,6 +263,7 @@ static void pollInputUpdates() {
pushToAll(QUEUE_PEN, evt(EV_ABS, ABS_PRESSURE, dTranslate));
pushToAll(QUEUE_PEN, evt(EV_SYN, SYN_REPORT, 0));
break;

case INPUT_BTN_PRESS:
pushToAll(QUEUE_BUTTONS, evt(EV_KEY, mapKey(message.userInput.x), 1));
pushToAll(QUEUE_BUTTONS, evt(EV_SYN, SYN_REPORT, 0));
Expand All @@ -225,6 +272,42 @@ static void pollInputUpdates() {
pushToAll(QUEUE_BUTTONS, evt(EV_KEY, mapKey(message.userInput.x), 0));
pushToAll(QUEUE_BUTTONS, evt(EV_SYN, SYN_REPORT, 0));
break;

case INPUT_VKB_PRESS: {
auto [keySym, isShifted] = mapAsciiToX11Key(message.userInput.x);

if (keySym != 0x0000) {
if (isShifted) {
pushToAll(QUEUE_VIRTUALKEYBOARD, evt(EV_KEY, 0xffe1, 1));
pushToAll(QUEUE_VIRTUALKEYBOARD, evt(EV_SYN, SYN_REPORT, 0));
}

usleep(10000);

pushToAll(QUEUE_VIRTUALKEYBOARD, evt(EV_KEY, keySym, 1));
pushToAll(QUEUE_VIRTUALKEYBOARD, evt(EV_SYN, SYN_REPORT, 0));
}

break;
}
case INPUT_VKB_RELEASE: {
auto [keySym, isShifted] = mapAsciiToX11Key(message.userInput.x);

if (keySym != 0x0000) {
pushToAll(QUEUE_VIRTUALKEYBOARD, evt(EV_KEY, keySym, 0));
pushToAll(QUEUE_VIRTUALKEYBOARD, evt(EV_SYN, SYN_REPORT, 0));

usleep(10000);

if (isShifted) {
pushToAll(QUEUE_VIRTUALKEYBOARD, evt(EV_KEY, 0xffe1, 0));
pushToAll(QUEUE_VIRTUALKEYBOARD, evt(EV_SYN, SYN_REPORT, 0));
}
}

break;
}

default: break;
}
}
Expand Down Expand Up @@ -267,6 +350,7 @@ int inputShimOpen(fileident_t identity, int flags, mode_t mode) {
e("dig", *identDigitizer);
e("tch", *identTouchScreen);
e("btn", *identButtons);
e("vkb", *identVirtualKeyboard);
e("null", *identNull);
#undef e
if(identDigitizer->find(identity) != identDigitizer->end()) {
Expand All @@ -285,6 +369,11 @@ int inputShimOpen(fileident_t identity, int flags, mode_t mode) {
CERR << "Open buttons " << fd << std::endl;
return fd;
}
if(identVirtualKeyboard->find(identity) != identVirtualKeyboard->end()) {
int fd = createInEventMap(QUEUE_VIRTUALKEYBOARD, flags);
CERR << "Open virtual keyboard " << fd << std::endl;
return fd;
}
if(identNull->find(identity) != identNull->end()) {
int fd = createInEventMap(QUEUE_NULL, flags);
CERR << "Open null " << fd << std::endl;
Expand Down
17 changes: 15 additions & 2 deletions shim/src/shim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <string>
#include <sstream>
#include <unistd.h>
#include <fstream>
#include "shim.h"
#include "fb-shim.h"
#include "input-shim.h"
Expand Down Expand Up @@ -40,7 +41,7 @@ bool shimModel;
bool shimInput;
bool shimFramebuffer;
int shimInputType = SHIM_INPUT_RM1;
std::set<fileident_t> *identDigitizer, *identTouchScreen, *identButtons, *identNull;
std::set<fileident_t> *identDigitizer, *identTouchScreen, *identButtons, *identVirtualKeyboard, *identNull;
int realDeviceType;

void readRealDeviceType() {
Expand Down Expand Up @@ -108,6 +109,7 @@ void __attribute__((constructor)) __construct () {
identDigitizer = new std::set<fileident_t>();
identTouchScreen = new std::set<fileident_t>();
identButtons = new std::set<fileident_t>();
identVirtualKeyboard = new std::set<fileident_t>();
identNull = new std::set<fileident_t>();

readRealDeviceType();
Expand Down Expand Up @@ -192,7 +194,10 @@ void __attribute__((constructor)) __construct () {
CERR << "Configured FB type to " << shimType << ", input to " << shimInputType << std::endl;


const char *pathDigitizer, *pathTouchScreen, *pathButtons, *pathNull;
const char *pathDigitizer, *pathTouchScreen, *pathButtons, *pathVirtualKeyboard, *pathNull;

pathVirtualKeyboard = "/dev/input/virtual_keyboard";
std::ofstream(pathVirtualKeyboard).close();

switch(shimInputType) {
case SHIM_INPUT_RM1:
Expand Down Expand Up @@ -233,6 +238,11 @@ void __attribute__((constructor)) __construct () {
}
iterStringCollectToIdentities(identButtons, temp);

if((temp = getenv("QTFB_SHIM_INPUT_PATH_KEYS")) == NULL) {
temp = pathVirtualKeyboard;
}
iterStringCollectToIdentities(identVirtualKeyboard, temp);

if((temp = getenv("QTFB_SHIM_INPUT_PATH_NULL")) == NULL) {
temp = pathNull;
}
Expand All @@ -247,6 +257,9 @@ void __attribute__((constructor)) __construct () {
for(const auto e : *identButtons) {
CERR << "Ident btn: " << e << std::endl;
}
for(const auto e : *identVirtualKeyboard) {
CERR << "Ident vkb: " << e << std::endl;
}
for(const auto e : *identNull) {
CERR << "Ident null: " << e << std::endl;
}
Expand Down
9 changes: 7 additions & 2 deletions src/AppLibrary.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class AppLoadApplication : public QObject {
Q_PROPERTY(QString name READ name CONSTANT)
Q_PROPERTY(QString icon READ icon CONSTANT)
Q_PROPERTY(bool supportsScaling READ supportsScaling)
Q_PROPERTY(bool supportsVirtualKeyboard READ supportsVirtualKeyboard)
Q_PROPERTY(bool canHaveMultipleFrontends READ canHaveMultipleFrontends)
Q_PROPERTY(int externalType READ externalType) // 0 - not external, 1 - external (non-graphics), 2 - external (qtfb)
Q_PROPERTY(QString aspectRatio READ aspectRatio CONSTANT)
Expand All @@ -32,14 +33,15 @@ class AppLoadApplication : public QObject {
public:
explicit AppLoadApplication(QObject *parent = nullptr)
: QObject(parent) {}
AppLoadApplication(const QString &id, const QString &name, const QString &icon, bool supportsScaling, bool canHaveMultipleFrontends, int externalType, appload::library::AspectRatio aspectRatio, bool disablesWindowedMode, QObject *parent = nullptr)
: QObject(parent), _id(id), _name(name), _icon(icon), _supportsScaling(supportsScaling), _canHaveMultipleFrontends(canHaveMultipleFrontends), _externalType(externalType), _aspectRatio(aspectRatio), _disablesWindowedMode(disablesWindowedMode) {}
AppLoadApplication(const QString &id, const QString &name, const QString &icon, bool supportsScaling, bool supportsVirtualKeyboard, bool canHaveMultipleFrontends, int externalType, appload::library::AspectRatio aspectRatio, bool disablesWindowedMode, QObject *parent = nullptr)
: QObject(parent), _id(id), _name(name), _icon(icon), _supportsScaling(supportsScaling), _supportsVirtualKeyboard(supportsVirtualKeyboard), _canHaveMultipleFrontends(canHaveMultipleFrontends), _externalType(externalType), _aspectRatio(aspectRatio), _disablesWindowedMode(disablesWindowedMode) {}

QString id() const { return _id; }
QString name() const { return _name; }
QString icon() const { return _icon; }
QString aspectRatio() const { return appload::library::aspectRatioToString(_aspectRatio); }
bool supportsScaling() const { return _supportsScaling; }
bool supportsVirtualKeyboard() const { return _supportsVirtualKeyboard; }
bool canHaveMultipleFrontends() const { return _canHaveMultipleFrontends; }
int externalType() const { return _externalType; }
bool disablesWindowedMode() const { return _disablesWindowedMode; }
Expand All @@ -49,6 +51,7 @@ class AppLoadApplication : public QObject {
QString _name;
QString _icon;
bool _supportsScaling;
bool _supportsVirtualKeyboard;
bool _canHaveMultipleFrontends;
int _externalType;
appload::library::AspectRatio _aspectRatio;
Expand Down Expand Up @@ -107,6 +110,7 @@ class AppLoadLibrary : public QObject {
entry.second->getAppName(),
entry.second->getIconPath(),
entry.second->supportsScaling(),
false,
entry.second->canHaveMultipleFrontends(),
INTERNAL,
appload::library::AspectRatio::AUTO,
Expand All @@ -118,6 +122,7 @@ class AppLoadLibrary : public QObject {
entry.second->getAppName(),
entry.second->getIconPath(),
false,
entry.second->supportsVirtualKeyboard(),
true,
entry.second->isQTFB() ? EXTERNAL_QTFB : EXTERNAL_NOGUI,
entry.second->getAspectRatio(),
Expand Down
2 changes: 2 additions & 0 deletions src/library.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ namespace appload::library {
bool isQTFB() const;
AspectRatio getAspectRatio() const;
bool disablesWindowedMode() const;
bool supportsVirtualKeyboard() const;

bool valid = false;

Expand All @@ -62,6 +63,7 @@ namespace appload::library {
std::map<QString, QString> environment;
bool _isQTFB;
bool _disablesWindowedMode;
bool _supportsVirtualKeyboard;
AspectRatio aspectRatio;

void parseManifest();
Expand Down
7 changes: 5 additions & 2 deletions src/libraryexternals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ void appload::library::removeGlobalLibraryHandle(AppLoadLibrary *ptr) {
}
}



void appload::library::ExternalApplication::parseManifest() {
QString filePath = root + "/external.manifest.json";
QFile file(filePath);
Expand All @@ -55,6 +53,7 @@ void appload::library::ExternalApplication::parseManifest() {
// Optional:
_isQTFB = jsonObject.value("qtfb").toBool(false);
_disablesWindowedMode = jsonObject.value("disablesWindowedMode").toBool(false);
_supportsVirtualKeyboard = jsonObject.value("supportsVirtualKeyboard").toBool(false);
workingDirectory = jsonObject.value("workingDirectory").toString(root);
args = jsonObject.value("args").toVariant().toStringList();
QJsonObject env = jsonObject.value("environment").toObject();
Expand Down Expand Up @@ -137,6 +136,10 @@ bool appload::library::ExternalApplication::disablesWindowedMode() const {
return _disablesWindowedMode;
}

bool appload::library::ExternalApplication::supportsVirtualKeyboard() const {
return _supportsVirtualKeyboard;
}

void appload::library::terminateExternal(qint64 pid) {
kill(pid, SIGTERM);
sendPidDiedMessage(pid);
Expand Down
Loading