summaryrefslogtreecommitdiff
path: root/windows/keybuddy2/src/hotstrings.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'windows/keybuddy2/src/hotstrings.cpp')
-rw-r--r--windows/keybuddy2/src/hotstrings.cpp268
1 files changed, 268 insertions, 0 deletions
diff --git a/windows/keybuddy2/src/hotstrings.cpp b/windows/keybuddy2/src/hotstrings.cpp
new file mode 100644
index 0000000..2c5a397
--- /dev/null
+++ b/windows/keybuddy2/src/hotstrings.cpp
@@ -0,0 +1,268 @@
+#include "includes.h"
+
+hotString* hotString::pHotStrings=NULL;
+int hotString::numHotStrings=0;
+WString hotString::hsBuffer;
+int hotString::bufferLen=0;
+long hotString::lastFocusPtr=0;
+
+// load all hotstrings from file
+void hotString::loadHotStrings(){
+
+ // in a first pass, just rush through the file and count the number of hotstrings
+
+ FILE* pFile;
+ int i;
+ char buffer;
+ wchar unibuffer;
+
+ #define FGETUC(pbuf,pfile) fread(pbuf,sizeof(wchar),1,pfile)
+
+ numHotStrings=0;
+ bool valueEnd;
+
+ pFile = fopen(SRCPATH "hotstrings.txt", "rb");
+ if (pFile==NULL) {PromptOK("Can't read hotstrings.txt"); exit(1);}
+
+ fgetc(pFile); // skip BOM
+ fgetc(pFile);
+
+ while(!feof(pFile)){
+ FGETUC(&unibuffer,pFile); // read identifier
+ if( unibuffer>=97 && unibuffer<=122 ){
+
+ FGETUC(&unibuffer,pFile); // read =
+ FGETUC(&unibuffer,pFile); // read "
+
+ valueEnd=false;
+ while(!valueEnd){
+ FGETUC(&unibuffer,pFile);
+ if(unibuffer==34){valueEnd=true;} // read " -> end of value
+ if(unibuffer==92){FGETUC(&unibuffer,pFile);} // read \ -> skip next character
+ }
+ FGETUC(&unibuffer,pFile); // read separator
+ if(unibuffer==13){ // line break -> entry complete
+ numHotStrings++;
+ FGETUC(&unibuffer,pFile); // read chr10
+ }
+ }
+ }
+
+ // now allocate as much memory as needed
+ pHotStrings = new hotString[numHotStrings];
+
+ // now go through in a second pass and store hotstrings
+ int iEntry=0;
+
+ rewind(pFile);
+
+ fgetc(pFile); // skip BOM
+ fgetc(pFile);
+
+ WString* pTarget=NULL;
+ fpos_t valueStart;
+ int valueLength;
+ bool isH;
+
+ while(!feof(pFile)){
+ FGETUC(&unibuffer,pFile); // read identifier
+ if(feof(pFile)){break;} // sometimes the first feof didnt indicate the end, so check again after read operatio
+
+ isH=false;
+
+ switch(unibuffer){
+ case 'h':
+ case 'H':
+ pTarget=&(hotString::pHotStrings[iEntry].hs);
+ isH=true;
+ break;
+ case 'c':
+ case 'C':
+ pTarget=&(hotString::pHotStrings[iEntry].winClass);
+ break;
+ case 't':
+ case 'T':
+ pTarget=&(hotString::pHotStrings[iEntry].winTitle);
+ break;
+ case 's':
+ case 'S':
+ pTarget=&(hotString::pHotStrings[iEntry].value);
+ hotString::pHotStrings[iEntry].launch=false;
+ break;
+ case 'l':
+ case 'L':
+ pTarget=&(hotString::pHotStrings[iEntry].value);
+ hotString::pHotStrings[iEntry].launch=true;
+ break;
+ default:
+ PromptOK("Error parsing hotstrings.txt: unknown element"); exit(1);
+ }
+
+ FGETUC(&unibuffer,pFile); // read =
+ FGETUC(&unibuffer,pFile); // read "
+
+ fgetpos(pFile, &valueStart);
+
+ // read value first to determine its length, then again and store
+
+ valueEnd=false;
+ valueLength=0;
+ while(!valueEnd){
+ FGETUC(&unibuffer,pFile);
+ if(unibuffer==34){ // read " -> end of value
+ valueEnd=true;
+ }
+ else{
+ if(unibuffer==92){ // read \ -> dont check next character
+ FGETUC(&unibuffer,pFile);
+ valueLength++;
+ }
+ else{ // increase number of chars
+ valueLength++;
+ }
+ }
+ }
+
+ if(isH && valueLength>bufferLen){
+ bufferLen=valueLength;
+ }
+
+ *pTarget = WString(0,valueLength);
+ fsetpos(pFile, &valueStart);
+ for(i=0;i<valueLength;i++){
+ FGETUC(&unibuffer,pFile);
+ if(unibuffer==92){FGETUC(&unibuffer,pFile);} // read \ -> skip to next character
+ pTarget->Set(i,unibuffer);
+ }
+
+ FGETUC(&unibuffer,pFile); // read "
+ FGETUC(&unibuffer,pFile); // read separator
+ if(unibuffer==13){ // line break -> entry complete
+ LOGG("Read hotstring: hs=");LOGG(pHotStrings[iEntry].hs);
+ LOGG(" winTitle=");LOGG(pHotStrings[iEntry].winTitle);
+ LOGG(" winClass=");LOGG(pHotStrings[iEntry].winClass);
+ LOGG(" value=");LOGG(pHotStrings[iEntry].value);LOGGNL;
+ iEntry++;
+ FGETUC(&unibuffer,pFile); // read chr10
+ }
+ }
+ fclose(pFile);
+
+ // create log buffer as long as the longest hotstring
+ hsBuffer = WString(0,bufferLen);
+
+ // sort list
+ qsort(pHotStrings,numHotStrings,sizeof(hotString),compareHotStrings);
+
+}
+
+// compare the hotstringbuffer to all hotstrings and fire if there is a match
+// to be more efficient, this could be done using a trie
+// however, c++ takes very few time to compare thousands of strings, so this was
+// not considered necessary
+void hotString::checkHotStrings(){
+ int i,k;
+ bool hit;
+
+ for(i=0;i<numHotStrings;i++){
+
+ if(pHotStrings[i].hs.IsEqual(hsBuffer.Right(pHotStrings[i].hs.GetLength()))){ // current hotstring matches typed letters
+
+ hit=false;
+
+ if(pHotStrings[i].winClass.IsEmpty() && pHotStrings[i].winTitle.IsEmpty()){ // no further conditions, send
+ hit=true;
+ }
+ else{ // check if focus object class and foreground window title match
+ WString wt,oc;
+ getFocusInfo(oc,wt);
+
+ if( (pHotStrings[i].winClass.IsEmpty() || pHotStrings[i].winClass.IsEqual(oc))
+ && (pHotStrings[i].winTitle.IsEmpty() || wt.Find(pHotStrings[i].winTitle)>-1) ){ // ok, everything matches, fire!
+
+ hit=true;
+ }
+ }
+
+ if(hit){
+
+ for(k=0;k<pHotStrings[i].hs.GetLength();k++){ // backspaces to delete the typement
+ KeyBuddy2::SendUNIKey(0xF008,false,HOTSTRING);
+ KeyBuddy2::SendUNIKey(0xF008,true,HOTSTRING);
+ }
+
+ if(!pHotStrings[i].launch){ // send string
+ for(k=0;k<pHotStrings[i].value.GetLength();k++){
+ KeyBuddy2::SendUNIKey(pHotStrings[i].value[k],false,HOTSTRING);
+ KeyBuddy2::SendUNIKey(pHotStrings[i].value[k],true,HOTSTRING);
+ }
+ break;
+ clearBuffer();
+ }
+ else{ // launch program
+ WString cmd=pHotStrings[i].value;
+
+ WString path,exe,params;
+ int delim1=-2,delim2=-2;
+
+ delim1=cmd.Find("|");
+ if(delim1==-1){
+ path="";
+ exe=cmd;
+ params="";
+ }
+ else{
+ delim2=cmd.Find("|",delim1+1);
+
+ if(delim2==-1){
+ path=cmd.Left(delim1);
+ exe=cmd.Mid(delim1+1);;
+ params="";
+ }
+ else{
+ path=cmd.Left(delim1);
+ exe=cmd.Mid(delim1+1,delim2-delim1-1);
+ params=cmd.Mid(delim2+1);
+ }
+ }
+
+ ShellExecuteW( NULL, NULL, exe, params, path, SW_SHOWNORMAL );
+
+ LOGG("working directory: ");LOGG(path);LOGGNL;
+ LOGG("exe: ");LOGG(exe);LOGGNL;
+ LOGG("params: ");LOGG(params);LOGGNL;
+ }
+ }
+ }
+ }
+}
+
+long hotString::getFocusWindowPtr(){
+
+ DWORD unused;
+
+ long myThread=GetWindowThreadProcessId(KeyBuddy2::pKB2->GetHWND(),&unused);
+ long otherThread=GetWindowThreadProcessId(GetForegroundWindow(),&unused);
+
+ if(myThread!=otherThread){
+ AttachThreadInput(otherThread,myThread,true);
+ }
+
+ long result=(long)GetFocus();
+
+ if(myThread!=otherThread){
+ AttachThreadInput(otherThread,myThread,false);
+ }
+
+ return result;
+}
+
+void hotString::getFocusInfo(WString& objectClass, WString& parentTitle){
+
+ char buffer[256];
+ GetClassName((HWND)getFocusWindowPtr(),buffer,255);
+ objectClass=WString(buffer);
+
+ GetWindowText(GetForegroundWindow(),buffer,255);
+ parentTitle=WString(buffer);
+}