I'm working on creating a command-line interface (CLI) editor similar to Vim for Windows using WinAPIs. Currently, I'm focusing on implementing the logic for the Edit mode (triggered by pressing 'i') and the Command mode (activated by pressing Escape), so I know of two approaches for this problem :
1.) The first approach is to create a while loop that continuously listens for the Escape key. This loop would run indefinitely on a separate thread to avoid interfering with the program flow. but the main issue with this one is this method may lead to high CPU consumption, slowing down the program and potentially causing CPU-related issues.
2.) The second approach involves using Windows hooks. I've written a simple program to intercept keyboard events and detect the 'i' and Escape keys. I've implemented a separate variable to track where the key press originates from. But, I'm encountering issues with the editor as it doesn't seem to work properly and the cursor remains in its previous position no matter whichever key we press during it's execution. Can please someone help me in here ?. ThankYou.
Here's the code for the same :-
HANDLE hConsole;
bool editMode = true;
void moveCursorToLastRow();
void moveCursorToFirstRow();
LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= 0) {
KBDLLHOOKSTRUCT* kbStruct = (KBDLLHOOKSTRUCT*)lParam;
DWORD vkCode = kbStruct->vkCode;
if (vkCode == VK_ESCAPE && editMode == true) {
editMode = false;
moveCursorToLastRow();
}
else if (vkCode == 'I' && editMode == false) {
editMode = true;
moveCursorToFirstRow();
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
void moveCursorToFirstRow() {
// Set the cursor position to the first row
COORD cursorPosition = { 3, 2 };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cursorPosition);
}
void moveCursorToLastRow() {
// Get the console screen buffer size
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
// Set the cursor position to the last row
COORD cursorPosition = { 3, csbi.dwSize.Y - 1 };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cursorPosition);
}
int main(int argc, char* argv[]) {
HINSTANCE hInstance = GetModuleHandle(NULL);
HHOOK hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProc, hInstance, 0);
if (hKeyboardHook == NULL) {
std::cerr << "Failed to install keyboard hook\n" << GetLastError();
return 1;
}
I tried Chatgpt for this problem but it just worsens the code, and instructed me to implemet a loop which would intercept the messages from the hooks chain, trying doing so but rather got stucked on an infinte loop and nothing got showed on the screen when tried to execute my program.
This is some example code that busy loops waiting for a key press. Normally, these types of loops are considered bad, but I think it is ok with this type of application.
ReadConsoleInputblocks until an input record has been read, so it's not constantly looping.Note: I just wrote this, so it is far from complete. Also, I've never written a program like this, so there may be better ways.
Another option would be to put the
getcharfunction in a separate thread and use events to alert the main program that there is input available.