summaryrefslogtreecommitdiff
Side-by-side diff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--inputmethods/multikey/configdlg.cpp238
-rw-r--r--inputmethods/multikey/configdlg.h8
-rw-r--r--inputmethods/multikey/keyboard.cpp42
-rw-r--r--inputmethods/multikey/keyboard.h2
4 files changed, 209 insertions, 81 deletions
diff --git a/inputmethods/multikey/configdlg.cpp b/inputmethods/multikey/configdlg.cpp
index a8206b7..f127d0e 100644
--- a/inputmethods/multikey/configdlg.cpp
+++ b/inputmethods/multikey/configdlg.cpp
@@ -5,29 +5,31 @@
* make keys translucent
* make vertical keys possible
*
*
*/
#include <qpe/qpeapplication.h>
#include <qpe/config.h>
+#include <qpe/resource.h>
#include <qwidget.h>
#include <qdialog.h>
#include <qtabwidget.h>
#include <qvbox.h>
#include <qgrid.h>
#include <qgroupbox.h>
#include <qlabel.h>
#include <qcheckbox.h>
#include <qsizepolicy.h>
#include <qpushbutton.h>
#include <qlistbox.h>
#include <qstringlist.h>
+#include <qtoolbutton.h>
#include <opie/ofiledialog.h>
#include <opie/colordialog.h>
#include <qdir.h>
#include <qfileinfo.h>
#include "configdlg.h"
#include "keyboard.h"
// ConfigDlg::ConfigDlg() {{{1
@@ -43,140 +45,135 @@ ConfigDlg::ConfigDlg () : QTabWidget ()
*/
QVBox *gen_box = new QVBox (this);
gen_box->setMargin(3);
addTab(gen_box, tr("General Settings"));
QGroupBox *map_group = new QGroupBox (2, Qt::Vertical, tr("Keymap File"), gen_box);
- keymaps = new QListBox (map_group);
+ QHBox *hbox1 = new QHBox(map_group);
+ keymaps = new QListBox(hbox1);
keymaps->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+ QVBox *vbox1 = new QVBox(hbox1);
+
+ QToolButton *tb1 = new QToolButton(vbox1, tr("Move Up"));
+ tb1->setPixmap(Resource::loadPixmap("up"));
+ tb1->setAutoRaise(TRUE);
+ tb1->setFocusPolicy(QWidget::NoFocus);
+ tb1->setToggleButton(FALSE);
+ connect(tb1, SIGNAL(clicked()), this, SLOT(moveSelectedUp()));
+
+ QToolButton *tb2 = new QToolButton(vbox1, tr("Move Down"));
+ tb2->setPixmap(Resource::loadPixmap("down"));
+ tb2->setAutoRaise(TRUE);
+ tb2->setFocusPolicy(QWidget::NoFocus);
+ tb2->setToggleButton(FALSE);
+ connect(tb2, SIGNAL(clicked()), this, SLOT(moveSelectedDown()));
QString cur(tr("Current Language"));
keymaps->insertItem(cur);
keymaps->setSelected(0, true);
QDir map_dir(QPEApplication::qpeDir() + "/share/multikey", "*.keymap");
default_maps = map_dir.entryList(); // so i can access it in other places
-
- for (uint i = 0; i < map_dir.count(); i++) {
-
- QFile map (map_dir.absPath() + "/" + map_dir[i]);
- if (map.open(IO_ReadOnly)) {
-
- QString line; bool found = 0;
-
- map.readLine(line, 1024);
- while (!map.atEnd()) {
-
- if (line.find(QRegExp("^title\\s*=\\s*")) != -1) {
-
- keymaps->insertItem(line.right(line.length() - line.find(QChar('=')) - 1).stripWhiteSpace());
- found = 1;
- break;
- }
- map.readLine(line, 1024);
- }
- if (!found) keymaps->insertItem(map_dir.absPath() + "/" + map_dir[i]);
-
- map.close();
- }
- if (map_dir.absPath() + "/" + map_dir[i] == current_map) {
-
- keymaps->setSelected(i + 1, true);
- }
-
- }
-
custom_maps = config.readListEntry("maps", QChar('|'));
+ sw_maps = ConfigDlg::loadSw();
- for (uint i = 0; i < custom_maps.count(); i++) {
+ QStringList sw_copy(sw_maps);
+ for (uint i = 0; i < sw_copy.count(); i++) {
- if (map_dir.exists(QFileInfo(custom_maps[i]).fileName(), false)
- || !QFile::exists(custom_maps[i])) {
+ QString keymap_map;
+ if (sw_copy[i][0] != '/') { /* share/multikey */
- custom_maps.remove(custom_maps.at(i));
+ keymap_map = map_dir.absPath() + "/" + sw_copy[i];
+ } else {
- // remove it from the list too
- config.writeEntry("maps", custom_maps.join("|"));
+ if (map_dir.exists(QFileInfo(sw_copy[i]).fileName(), false)
+ || !QFile::exists(sw_copy[i])) {
+ custom_maps.remove(sw_copy[i]);
+ sw_maps.remove(sw_copy[i]);
- } else {
+ // remove it from the list too
+ config.writeEntry("maps", custom_maps.join("|"));
- QFile map (custom_maps[i]);
- if (map.open(IO_ReadOnly)) {
+ continue;
+ }
+ keymap_map = sw_copy[i];
+ }
- QString line; bool found = 0;
+ QFile map(keymap_map);
+ if (map.open(IO_ReadOnly)) {
- map.readLine(line, 1024);
- while (!map.atEnd()) {
+ QString line; bool found = 0;
- if (line.find(QRegExp("^title\\s*=\\s*")) != -1) {
-
- keymaps->insertItem(line.right(line.length() - line.find(QChar('=')) - 1).stripWhiteSpace());
- found = 1;
- break;
- }
- map.readLine(line, 1024);
- }
- if (!found) keymaps->insertItem(custom_maps[i]);
-
- map.close();
- }
- if (custom_maps[i] == current_map) {
+ map.readLine(line, 1024);
+ while (!map.atEnd()) {
- keymaps->setSelected(map_dir.count() + i + 1, true);
- }
- }
+ if (line.find(QRegExp("^title\\s*=\\s*")) != -1) {
+
+ keymaps->insertItem(line.right(line.length() - line.find(QChar('=')) - 1).stripWhiteSpace());
+ found = 1;
+ break;
+ }
+ map.readLine(line, 1024);
+ }
+ if (!found)
+ keymaps->insertItem(keymap_map);
+
+ map.close();
+ }
+
+ if (keymap_map == current_map) {
+ keymaps->setSelected(i + 1, true);
+ }
}
// have to "+1" because the "current language" listItem... remember?
connect(keymaps, SIGNAL(highlighted(int)), SLOT(setMap(int)));
-
QGrid *add_remove_grid = new QGrid(2, map_group);
add_remove_grid->setMargin(3);
add_remove_grid->setSpacing(3);
add_button = new QPushButton(tr("Add"), add_remove_grid);
- add_button->setFlat((bool)1);
+ add_button->setFlat(TRUE);
connect(add_button, SIGNAL(clicked()), SLOT(addMap()));
remove_button = new QPushButton(tr("Remove"), add_remove_grid);
- remove_button->setFlat((bool)1);
- if ((int)map_dir.count() >= keymaps->currentItem())
- remove_button->setDisabled(true);
+ remove_button->setFlat(TRUE);
+ if (default_maps.find(QFileInfo(current_map).fileName()) != default_maps.end())
+ remove_button->setDisabled(true);
connect(remove_button, SIGNAL(clicked()), SLOT(removeMap()));
// make a box that will contain the buttons on the bottom
QGrid *other_grid = new QGrid(2, gen_box);
pick_button = new QCheckBox(tr("Pickboard"), other_grid);
config.setGroup ("general");
- bool pick_open = config.readBoolEntry ("usePickboard", (bool)0); // default closed
+ bool pick_open = config.readBoolEntry ("usePickboard", FALSE); // default closed
if (pick_open) {
pick_button->setChecked(true);
}
// by connecting it after checking it, the signal isn't emmited
connect (pick_button, SIGNAL(clicked()), this, SLOT(pickTog()));
repeat_button = new QCheckBox(tr("Key Repeat"), other_grid);
- bool repeat_on = config.readBoolEntry ("useRepeat", (bool)1);
+ bool repeat_on = config.readBoolEntry ("useRepeat", TRUE);
if (repeat_on) {
repeat_button->setChecked(true);
}
connect (repeat_button, SIGNAL(clicked()), this, SLOT(repeatTog()));
-
/*
* 'color' tab
*/
QGrid *color_box = new QGrid(2, this);
color_box->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
color_box->setMargin(3);
color_box->setSpacing(3);
@@ -184,56 +181,140 @@ ConfigDlg::ConfigDlg () : QTabWidget ()
QLabel *label;
QStringList color;
config.setGroup("colors");
label = new QLabel(tr("Key Color"), color_box);
keycolor_button = new QPushButton(color_box);
connect(keycolor_button, SIGNAL(clicked()), SLOT(keyColorClicked()));
- keycolor_button->setFlat((bool)1);
+ keycolor_button->setFlat(TRUE);
color = config.readListEntry("keycolor", QChar(','));
/*
* hopefully not required
if (color.isEmpty()) {
color = QStringList::split(",", "240,240,240");
config.writeEntry("keycolor", color.join(","));
}
*/
keycolor_button->setPalette(QPalette(QColor(color[0].toInt(), color[1].toInt(), color[2].toInt())));
label = new QLabel(tr("Key Pressed Color"), color_box);
keycolor_pressed_button = new QPushButton(color_box);
connect(keycolor_pressed_button, SIGNAL(clicked()), SLOT(keyColorPressedClicked()));
- keycolor_pressed_button->setFlat((bool)1);
+ keycolor_pressed_button->setFlat(TRUE);
color = config.readListEntry("keycolor_pressed", QChar(','));
keycolor_pressed_button->setPalette(QPalette((QColor(color[0].toInt(), color[1].toInt(), color[2].toInt()))));
label = new QLabel(tr("Line Color"), color_box);
keycolor_lines_button = new QPushButton(color_box);
connect(keycolor_lines_button, SIGNAL(clicked()), SLOT(keyColorLinesClicked()));
- keycolor_lines_button->setFlat((bool)1);
+ keycolor_lines_button->setFlat(TRUE);
color = config.readListEntry("keycolor_lines", QChar(','));
keycolor_lines_button->setPalette(QPalette((QColor(color[0].toInt(), color[1].toInt(), color[2].toInt()))));
label = new QLabel(tr("Text Color"), color_box);
textcolor_button = new QPushButton(color_box);
connect(textcolor_button, SIGNAL(clicked()), SLOT(textColorClicked()));
- textcolor_button->setFlat((bool)1);
+ textcolor_button->setFlat(TRUE);
color = config.readListEntry("textcolor", QChar(','));
textcolor_button->setPalette(QPalette((QColor(color[0].toInt(), color[1].toInt(), color[2].toInt()))));
-
label = new QLabel("", color_box); // a spacer so the above buttons dont expand
label->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+}
+
+ConfigDlg::~ConfigDlg()
+{
+ emit reloadSw();
+}
+
+QStringList ConfigDlg::loadSw()
+{
+ Config *config = new Config("multikey");
+ config->setGroup("keymaps");
+ QDir map_dir(QPEApplication::qpeDir() + "/share/multikey", "*.keymap");
+ QStringList d_maps = map_dir.entryList(); // so i can access it in other places
+ QStringList c_maps = config->readListEntry("maps", QChar('|'));
+ QStringList s_maps = config->readListEntry("sw", QChar('|'));
+ delete config;
+
+ if (!s_maps.count())
+ {
+ s_maps = d_maps+c_maps;
+ }
+ else
+ {
+ /* Clear non existents entries */
+ QStringList s_copy = s_maps;
+ for (uint i = 0; i < s_copy.count(); ++i) {
+ if (d_maps.find(s_copy[i]) == d_maps.end()
+ && c_maps.find(s_copy[i]) == c_maps.end()) {
+ s_maps.remove(s_copy[i]);
+ }
+ }
+ /* Update sw_maps from default_maps */
+ for (uint i = 0; i < d_maps.count(); ++i) {
+ if (s_maps.find(d_maps[i]) == s_maps.end()) {
+ s_maps.append(d_maps[i]);
+ }
+ }
+ /* Update sw_maps from custom_maps */
+ for (uint i = 0; i < c_maps.count(); ++i) {
+ if (s_maps.find(c_maps[i]) == s_maps.end()) {
+ s_maps.append(c_maps[i]);
+ }
+ }
+ }
+
+ return s_maps;
+}
+
+void ConfigDlg::moveSelectedUp()
+{
+ int i = keymaps->currentItem();
+ /* Ignore Current Language */
+ if (i > 1) {
+ QString t = sw_maps[i-1];
+ sw_maps[i-1] = sw_maps[i-2];
+ sw_maps[i-2] = t;
+
+ QString item = keymaps->currentText();
+ keymaps->removeItem(i);
+ keymaps->insertItem(item, i-1);
+ keymaps->setCurrentItem(i-1);
+
+ Config config("multikey");
+ config.setGroup("keymaps");
+ config.writeEntry("sw", sw_maps, QChar('|'));
+ }
+}
+void ConfigDlg::moveSelectedDown()
+{
+ int i = keymaps->currentItem();
+ /* Ignore Current Language */
+ if (i > 0 && i < (int)keymaps->count() - 1) {
+ QString t = sw_maps[i-1];
+ sw_maps[i-1] = sw_maps[i];
+ sw_maps[i] = t;
+
+ QString item = keymaps->currentText();
+ keymaps->removeItem(i);
+ keymaps->insertItem(item, i+1);
+ keymaps->setCurrentItem(i+1);
+
+ Config config("multikey");
+ config.setGroup("keymaps");
+ config.writeEntry("sw", sw_maps, QChar('|'));
+ }
}
void ConfigDlg::pickTog() {
Config config ("multikey");
config.setGroup ("general");
config.writeEntry ("usePickboard", pick_button->isChecked()); // default closed
@@ -266,40 +347,42 @@ void ConfigDlg::closeEvent(QCloseEvent *) {
void ConfigDlg::setMap(int index) {
if (index == 0) {
remove_button->setDisabled(true);
emit setMapToDefault();
}
- else if ((uint)index <= default_maps.count()) {
+ else if (default_maps.find(sw_maps[index-1]) != default_maps.end()) {
remove_button->setDisabled(true);
- emit setMapToFile(QPEApplication::qpeDir() + "share/multikey/" + default_maps[index - 1]);
+ emit setMapToFile(QPEApplication::qpeDir() + "share/multikey/" + sw_maps[index - 1]);
} else {
remove_button->setEnabled(true);
- emit setMapToFile(custom_maps[index - default_maps.count() - 1]);
+ emit setMapToFile(sw_maps[index - 1]);
}
}
// ConfigDlg::addMap() {{{1
void ConfigDlg::addMap() {
QString map = OFileDialog::getOpenFileName(1, QDir::home().absPath());
if (map.isNull()) return;
Config config ("multikey");
config.setGroup("keymaps");
QStringList maps = config.readListEntry("maps", QChar('|'));
maps.append(map);
custom_maps.append(map);
+ if (sw_maps.find(map) == sw_maps.end())
+ sw_maps.append(map);
QFile map_file (map);
if (map_file.open(IO_ReadOnly)) {
QString line; bool found = 0;
map_file.readLine(line, 1024);
while (!map_file.atEnd()) {
@@ -316,34 +399,37 @@ void ConfigDlg::addMap() {
map_file.close();
}
keymaps->setSelected(keymaps->count() - 1, true);
config.writeEntry("maps", maps, QChar('|'));
+ config.writeEntry("sw", sw_maps, QChar('|'));
config.writeEntry("current", map);
}
// ConfigDlg::removeMap() {{{1
void ConfigDlg::removeMap() {
// move selection up one
keymaps->setSelected(keymaps->currentItem() - 1, true);
// delete the next selected item cus you just moved it up
keymaps->removeItem(keymaps->currentItem() + 1);
- custom_maps.remove(custom_maps.at(keymaps->currentItem() - default_maps.count()));
+ custom_maps.remove(sw_maps[keymaps->currentItem()]);
+ sw_maps.remove(sw_maps.at(keymaps->currentItem()));
// write the changes
Config config ("multikey");
config.setGroup("keymaps");
config.writeEntry("maps", custom_maps, QChar('|'));
+ config.writeEntry("sw", sw_maps, QChar('|'));
}
/* ConfigDlg::slots for the color buttons {{{1
*
* these four slots are almost the same, except for the names. i was thinking
* of making a map with pointers to the buttons and names of the configEntry
* so it could be one slot, but then there would be no way of telling which
* of the buttons was clicked if they all connect to the same slot.
diff --git a/inputmethods/multikey/configdlg.h b/inputmethods/multikey/configdlg.h
index 336932b..ea157c5 100644
--- a/inputmethods/multikey/configdlg.h
+++ b/inputmethods/multikey/configdlg.h
@@ -8,24 +8,31 @@
#define CONFIGDLG_H
class ConfigDlg : public QTabWidget
{
Q_OBJECT
public:
ConfigDlg ();
+ ~ConfigDlg ();
+ static QStringList ConfigDlg::loadSw();
signals:
void pickboardToggled(bool on_off);
void repeatToggled(bool on_off);
void setMapToDefault();
void setMapToFile(QString map);
void reloadKeyboard();
void configDlgClosed();
+ void reloadSw();
+
+protected slots:
+ void moveSelectedUp();
+ void moveSelectedDown();
private slots:
void pickTog();
void repeatTog();
void setMap(int index);
void addMap();
void removeMap();
virtual void closeEvent ( QCloseEvent * );
@@ -42,16 +49,17 @@ private:
QCheckBox *repeat_button;
QListBox *keymaps;
QPushButton *add_button;
QPushButton *remove_button;
QStringList default_maps; // the maps in your share/multikey/ dir
QStringList custom_maps; // maps you added with the 'add' button
+ QStringList sw_maps; // maps, which used in keyboard switch rotation ring
/* color buttons */
QPushButton *keycolor_button;
QPushButton *keycolor_pressed_button;
QPushButton *keycolor_lines_button;
QPushButton *textcolor_button;
};
diff --git a/inputmethods/multikey/keyboard.cpp b/inputmethods/multikey/keyboard.cpp
index 2ce6dd3..aec0ad3 100644
--- a/inputmethods/multikey/keyboard.cpp
+++ b/inputmethods/multikey/keyboard.cpp
@@ -26,17 +26,17 @@
#include <qwindowsystem_qws.h>
#include <qpainter.h>
#include <qfontmetrics.h>
#include <qtimer.h>
#include <qpe/qpeapplication.h>
#include <qpe/config.h>
#include <ctype.h>
-#include <qfile.h>
+#include <qdir.h>
#include <qtextstream.h>
#include <qstringlist.h>
#include <sys/utsname.h>
using namespace MultiKey;
static const char * const kb_config_xpm[] = {
@@ -89,22 +89,25 @@ Keyboard::Keyboard(QWidget* parent, const char* _name, WFlags f) :
loadKeyboardColors();
keys = new Keys();
repeatTimer = new QTimer( this );
connect( repeatTimer, SIGNAL(timeout()), this, SLOT(repeat()) );
+ QCopChannel* kbdChannel = new QCopChannel("MultiKey/Keyboard", this);
+ connect(kbdChannel, SIGNAL(received(const QCString &, const QByteArray &)),
+ this, SLOT(receive(const QCString &, const QByteArray &)));
}
Keyboard::~Keyboard() {
if ( configdlg ) {
- delete (ConfigDlg *) configdlg;
+ delete configdlg;
configdlg = 0;
}
}
/* Keyboard::resizeEvent {{{1 */
void Keyboard::resizeEvent(QResizeEvent*)
{
@@ -412,33 +415,35 @@ void Keyboard::mousePressEvent(QMouseEvent *e)
if (unicode == 0) { // either Qt char, or nothing
if (qkeycode == Qt::Key_F1) { // toggle the pickboard
if ( configdlg ) {
- delete (ConfigDlg *) configdlg;
+ delete configdlg;
configdlg = 0;
}
else {
configdlg = new ConfigDlg ();
connect(configdlg, SIGNAL(setMapToDefault()),
this, SLOT(setMapToDefault()));
connect(configdlg, SIGNAL(setMapToFile(QString)),
this, SLOT(setMapToFile(QString)));
connect(configdlg, SIGNAL(pickboardToggled(bool)),
this, SLOT(togglePickboard(bool)));
connect(configdlg, SIGNAL(repeatToggled(bool)),
this, SLOT(toggleRepeat(bool)));
connect(configdlg, SIGNAL(reloadKeyboard()),
this, SLOT(reloadKeyboard()));
connect(configdlg, SIGNAL(configDlgClosed()),
this, SLOT(cleanupConfigDlg()));
+ connect(configdlg, SIGNAL(reloadSw()),
+ this, SLOT(reloadSw()));
configdlg->showMaximized();
configdlg->show();
configdlg->raise();
}
} else if (qkeycode == Qt::Key_Control) {
need_repaint = TRUE;
@@ -755,16 +760,27 @@ void Keyboard::mousePressEvent(QMouseEvent *e)
}
if (useRepeat) repeatTimer->start( 800 );
//pressTid = startTimer(80);
}
+void Keyboard::receive(const QCString &msg, const QByteArray &data)
+{
+ if (msg == "setmultikey(QString)") {
+ QDataStream stream(data, IO_ReadOnly);
+ QString map;
+ stream >> map;
+ setMapToFile(map);
+ } else if (msg == "getmultikey()") {
+ reloadSw();
+ }
+}
/* Keyboard::mouseReleaseEvent {{{1 */
void Keyboard::mouseReleaseEvent(QMouseEvent*)
{
pressed = FALSE;
//if ( pressTid == 0 )
#if defined(Q_WS_QWS) || defined(_WS_QWS_)
if ( unicode != -1 ) {
@@ -906,31 +922,47 @@ void Keyboard::toggleRepeat(bool on) {
useRepeat = on;
//cout << "setting useRepeat to: " << useRepeat << "\n";
}
void Keyboard::cleanupConfigDlg() {
if ( configdlg ) {
- delete (ConfigDlg *) configdlg;
+ delete configdlg;
configdlg = 0;
}
}
+void Keyboard::reloadSw() {
+ QCopEnvelope e("MultiKey/Switcher", "setsw(QString,QString)");
+
+ Config* config = new Config("multikey");
+ config->setGroup("keymaps");
+ QString current_map = config->readEntry("current", "en.keymap");
+ delete config;
+
+ e << ConfigDlg::loadSw().join("|") << current_map;
+}
+
/* Keyboard::setMapTo ... {{{1 */
void Keyboard::setMapToDefault() {
/* load current locale language map */
Config *config = new Config("locale");
config->setGroup( "Language" );
QString l = config->readEntry( "Language" , "en" );
delete config;
+ /* if Language represents as en_US, ru_RU, etc... */
+ int d = l.find('_');
+ if (d != -1) {
+ l.remove(d, l.length()-d);
+ }
QString key_map = QPEApplication::qpeDir() + "share/multikey/"
+ l + ".keymap";
/* save change to multikey config file */
config = new Config("multikey");
config->setGroup ("keymaps");
config->writeEntry ("current", key_map); // default closed
delete config;
@@ -1501,17 +1533,17 @@ void Keys::setKeysFromFile(const char * filename) {
QChar d;
tmp >> d >> lower >> shift;
accentMap.insert(lower, shift);
buf = t.readLine();
}
- // other variables like lang & title
+ // other variables like lang & title & sw
else if (buf.contains(QRegExp("^\\s*[a-zA-Z]+\\s*=\\s*[a-zA-Z0-9/]+\\s*$", FALSE, FALSE))) {
QTextStream tmp (buf, IO_ReadOnly);
QString name, equals, value;
tmp >> name >> equals >> value;
if (name == "lang") {
diff --git a/inputmethods/multikey/keyboard.h b/inputmethods/multikey/keyboard.h
index 20c5cee..0b56988 100644
--- a/inputmethods/multikey/keyboard.h
+++ b/inputmethods/multikey/keyboard.h
@@ -125,19 +125,21 @@ signals:
private slots:
void repeat();
void togglePickboard(bool on_off);
void toggleRepeat(bool on_off);
void setMapToDefault();
void setMapToFile(QString map);
void cleanupConfigDlg();
+ void reloadSw();
// used to redraw keyboard after edited colors
void reloadKeyboard();
+ void receive( const QCString &msg, const QByteArray &data );
private:
int getKey( int &w, int j = -1 );
void clearHighlight();
bool *shift;
bool *lock;
bool *ctrl;