1 //===========================================
2 // Lumina desktop source code
3 // Copyright (c) 2017, Ken Moore
4 // Available under the 3-clause BSD license
5 // See the LICENSE file for full details
6 //===========================================
7 #include "LShortcutEvents.h"
8 #include "global-objects.h"
9
10 // === PUBLIC ===
LShortcutEvents()11 LShortcutEvents::LShortcutEvents(){
12 WIN = 0;
13 clearTimer = 0;
14 evaluated = false;
15 }
16
~LShortcutEvents()17 LShortcutEvents::~LShortcutEvents(){
18
19 }
20
start()21 void LShortcutEvents::start(){
22 if(clearTimer==0){
23 clearTimer = new QTimer(this);
24 clearTimer->setInterval(2000); //2 seconds
25 clearTimer->setSingleShot(true);
26 connect(clearTimer, SIGNAL(timeout()), this, SLOT(clearKeys()) );
27 }
28 }
29
stop()30 void LShortcutEvents::stop(){
31 clearKeys();
32 }
33
34 // === PRIVATE ===
CheckKeySequence(WId win)35 void LShortcutEvents::CheckKeySequence(WId win){
36 //Get the keyboard modifiers
37 QString shortcut = keylistToString();
38 //Now see if there is a match for this shortcut
39 // "strict" actions (operate even if a non-desktop window is active/focused)
40 QString action = DesktopSettings::instance()->value(DesktopSettings::Keys, "strict/"+shortcut, "").toString();
41 qDebug() << "Strict Action:" << "strict/"+shortcut << action;
42 if(action.isEmpty() && win==0){
43 //"loose" actions (operating on the desktop or root window itself)
44 action = DesktopSettings::instance()->value(DesktopSettings::Keys, "desktop/"+shortcut, "").toString();
45 qDebug() << "Desktop Action:" << "desktop/"+shortcut << action;
46 }
47 if(!action.isEmpty()){
48 //Found a valid action - go ahead and evaluate it
49 evaluateShortcutAction(action);
50 }
51 }
52
CheckMouseSequence(WId win,NativeWindowSystem::MouseButton button,bool release)53 void LShortcutEvents::CheckMouseSequence(WId win, NativeWindowSystem::MouseButton button, bool release){
54 if(release && (button == NativeWindowSystem::WheelUp || button == NativeWindowSystem::WheelDown || button == NativeWindowSystem::WheelLeft || button == NativeWindowSystem::WheelRight)){
55 return; //skip mouse release events for wheel actions (always come in pairs of press/release)
56 }else if(keylist.isEmpty() || button == NativeWindowSystem::NoButton){ return; } //Never overwrite mouse clicks themselves - just combinations with key presses
57 //Get the keyboard modifiers
58 QString shortcut = keylistToString();
59 //Add the mouse button to the shortcut
60 switch(button){
61 case NativeWindowSystem::LeftButton:
62 shortcut.append("+LeftMouse");
63 break;
64 case NativeWindowSystem::RightButton:
65 shortcut.append("+RightMouse");
66 break;
67 case NativeWindowSystem::MidButton:
68 shortcut.append("+MiddleMouse");
69 break;
70 case NativeWindowSystem::BackButton:
71 shortcut.append("+BackMouse");
72 break;
73 case NativeWindowSystem::ForwardButton:
74 shortcut.append("+ForwardMouse");
75 break;
76 case NativeWindowSystem::TaskButton:
77 shortcut.append("+TaskMouse");
78 break;
79 case NativeWindowSystem::WheelUp:
80 shortcut.append("+WheelUp");
81 break;
82 case NativeWindowSystem::WheelDown:
83 shortcut.append("+WheelDown");
84 break;
85 case NativeWindowSystem::WheelLeft:
86 shortcut.append("+WheelLeft");
87 break;
88 case NativeWindowSystem::WheelRight:
89 shortcut.append("+WheelRight");
90 break;
91 default:
92 shortcut.clear();
93 }
94 if(shortcut.isEmpty()){ return; }
95 //Now see if there is a match for this shortcut
96 // "strict" actions (operate even if a non-desktop window is active/focused)
97 QString action = DesktopSettings::instance()->value(DesktopSettings::Keys, "strict/"+shortcut, "").toString();
98 if(action.isEmpty() && win==0){
99 //"loose" actions (operating on the desktop or root window itself)
100 action = DesktopSettings::instance()->value(DesktopSettings::Keys, "desktop/"+shortcut, "").toString();
101 }
102 if(!action.isEmpty()){
103 //Found a valid action - go ahead and evaluate it
104 evaluateShortcutAction(action);
105 }
106 }
107
keylistToString()108 QString LShortcutEvents::keylistToString(){
109 if(keylist.isEmpty()){ return ""; }
110 QString shortcut;
111 QList<int> keys; int ckey = 0;
112 for(int i=0; i<keylist.length(); i++){
113 if(i == keylist.length()-1){ ckey+=keylist[i]; } //always treat the last key as a non-modifier
114 else if(keylist[i] == Qt::Key_Control){ ckey+=Qt::CTRL; } //use the modifier form of the key
115 else if(keylist[i] == Qt::Key_Alt){ ckey += Qt::ALT; }
116 else if(keylist[i] == Qt::Key_Shift){ ckey += Qt::SHIFT; }
117 else if(keylist[i] == Qt::Key_Meta){ ckey += Qt::META; }
118 else{ ckey+= keylist[i]; keys << ckey; ckey = 0; } //non-modifier - need to finish current mod+key combo and start a new one
119 }
120 if(ckey!=0){ keys << ckey; } //add in the last one as well
121 if(keys.length() < 1){ return ""; }
122 QKeySequence seq;
123 switch(keys.length()){
124 case 1:
125 seq = QKeySequence(keys[0]); break;
126 case 2:
127 seq = QKeySequence(keys[0], keys[1]); break;
128 case 3:
129 seq = QKeySequence(keys[0], keys[1], keys[2]); break;
130 default:
131 seq = QKeySequence(keys[0],keys[1], keys[2], keys[3]); break;
132 }
133 /*qDebug() << "KeyList to String:";
134 qDebug() << " keys:" << seq;
135 qDebug() << " string:" << seq.toString();*/
136 return seq.toString();
137 }
138
evaluateShortcutAction(QString action)139 void LShortcutEvents::evaluateShortcutAction(QString action){
140 qDebug() << "Found Shortcut Action:" << action;
141 evaluated = true;
142 if(action.startsWith("Exec:")){
143 emit LaunchApplication(action.section(":",1,-1));
144 return;
145 }else if(action.startsWith("Launch:")){
146 emit LaunchStandardApplication(action.section(":",1,-1));
147 }
148 //Specific Internal actions
149 action = action.toLower();
150 //Power Options
151 if(action=="logout"){ emit StartLogout(); }
152 else if(action=="reboot"){ emit StartReboot(); }
153 else if(action=="shutdown"){ emit StartShutdown(); }
154 else if(action=="show_leave_options"){ emit OpenLeaveDialog(); }
155 else if(action=="lockscreen"){ emit LockSession(); }
156
157 }
158
159 // === PUBLIC SLOTS ===
KeyPress(WId window,Qt::Key key)160 void LShortcutEvents::KeyPress(WId window, Qt::Key key){
161 if(window!=WIN){ keylist.clear(); WIN = window; }
162 /*if(!keylist.contains(key)){
163 //Put it in the list in ascending order
164 bool found = false;
165 for(int i=0; i<keylist.length() && !found; i++){
166 if(keylist[i]>key){ keylist.insert(i,key); found = true; }
167 }
168 if(!found){ keylist << key; }
169 evaluated = false;
170 }*/
171 if(!keylist.isEmpty()){
172 if( keylist.last()!=key ){ keylist << key; }
173 }else{
174 keylist << key;
175 }
176 //Evaluate the key sequence only when the first one is released
177 clearTimer->start(); //will "restart" if already running
178 }
179
KeyRelease(WId window,Qt::Key key)180 void LShortcutEvents::KeyRelease(WId window, Qt::Key key){
181 if(window!=WIN){ keylist.clear(); return; }
182 if(!evaluated){ CheckKeySequence(WIN); } //run this "before" removing the key from the list
183 for(int i=keylist.length()-1; i>=0; i--){
184 if(keylist[i] == key){ keylist.removeAt(i); break; }
185 }
186 clearTimer->start(); //will "restart" if already running
187 }
188
MousePress(WId window,NativeWindowSystem::MouseButton button)189 void LShortcutEvents::MousePress(WId window, NativeWindowSystem::MouseButton button){
190 //We do not provide shortcuts for combinations of mouse buttons - just mouse+keyboard combinations
191 CheckMouseSequence(window, button, false);
192 clearTimer->start(); //will "restart" if already running
193 }
194
MouseRelease(WId window,NativeWindowSystem::MouseButton button)195 void LShortcutEvents::MouseRelease(WId window, NativeWindowSystem::MouseButton button){
196 //We do not provide shortcuts for combinations of mouse buttons - just mouse+keyboard combinations
197 CheckMouseSequence(window, button, true);
198 clearTimer->start(); //will "restart" if already running
199 }
200
clearKeys()201 void LShortcutEvents::clearKeys(){
202 keylist.clear();
203 WIN = 0;
204 if(clearTimer!=0){ clearTimer->stop(); }
205 }
206