U
compilierbares "minimal"bsp.:
(sendet "Hey" and nen fenster, dessen Name mit " - Editor" endet. das sollte bei nem deutschen windows notepad sein)
->
notepad öffnen
compilieren/ausführen
<-
#include <windows.h>
#include <stdexcept>
namespace keys
{
enum type : int
{
A = 'A', B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
NUM_0 = '0', NUM_1, NUM_2, NUM_3, NUM_4, NUM_5, NUM_6, NUM_7, NUM_8, NUM_9,
SPACE = VK_SPACE,
SHIFT = VK_SHIFT,
/*...*/
CTRL_L = VK_LCONTROL,
nothing = 0
};
}
struct key_send
{
key_send(keys::type key, bool manual_ctrl = false)
{
input.type = INPUT_KEYBOARD;
input.ki.time = 0;
input.ki.dwExtraInfo = 0;
input.ki.wVk = WORD(key);
if (key >= keys::A && key <= keys::Z || key == keys::SPACE || key >= keys::NUM_0 && key <= keys::NUM_9)
input.ki.dwFlags = KEYEVENTF_SCANCODE;
else
input.ki.dwFlags = KEYEVENTF_EXTENDEDKEY;
input.ki.wScan = WORD(MapVirtualKey(UINT(key), MAPVK_VK_TO_VSC));
if (!manual_ctrl)
press();
}
void press()
{
if (down)
return;
send();
}
void release()
{
if (!down)
return;
input.ki.dwFlags |= KEYEVENTF_KEYUP;
send();
}
~key_send()
{
try
{
release();
}
catch (...)
{
;
}
}
private:
void send()
{
auto events = SendInput(1, &input, sizeof(input));
if (events != 1)
throw std::runtime_error("SendInput");
down = !down;
}
bool down = false;
INPUT input;
};
#include <vector>
#include <cassert>
#include <cstring>
namespace window
{
using handle_t = HWND;
const handle_t no_handle = handle_t(0);
class thread_attacher
{
public:
thread_attacher(handle_t hwnd_from, handle_t hwnd_to)
{
from = ::GetWindowThreadProcessId(hwnd_from, 0);
to = ::GetWindowThreadProcessId(hwnd_to, 0);
::AttachThreadInput(from, to, true);
}
~thread_attacher()
{
::AttachThreadInput(from, to, false);
}
private:
DWORD from;
DWORD to;
};
inline void set_foreground_window(handle_t hwnd)
{
::SetForegroundWindow(hwnd);
}
inline handle_t get_foreground_window()
{
return ::GetForegroundWindow();
}
namespace detail
{
struct find_window_data
{
find_window_data(const char* title)
: title(title)
, handle(0)
{}
const char* title;
HWND handle;
};
struct wildcard_string
{
wildcard_string(const char* string)
: str(string)
{
if (std::strlen(str) > 1)
assert(!std::strchr(str + 1, '*') && "TODO");
}
bool operator== (const char* rhs) const
{
const char* lhs = str;
if (*lhs == '*')
return std::strstr(rhs, ++lhs) != nullptr;
return std::strcmp(lhs, rhs) == 0;
}
bool operator!= (const char* rhs) const
{
return !(*this == rhs);
}
private:
const char* str;
};
inline std::vector<char> get_title_from_hwnd(HWND hWnd)
{
const std::size_t MAX_LEN = 2048;
std::vector<char> ret_val(MAX_LEN);
int length = MAX_LEN - 1;
auto size_copyed = GetWindowTextA(hWnd, &ret_val[0], length);
ret_val.resize(static_cast<std::size_t>(size_copyed < 0 ? 0 : size_copyed + 1), '\0');
return ret_val;
}
inline BOOL CALLBACK find_window_impl(HWND hWnd, LPARAM lParam)
{
const BOOL call_next = TRUE;
const BOOL finished = FALSE;
find_window_data* data = reinterpret_cast<find_window_data*>(lParam);
assert(data && "invalid pointer");
std::vector<char> this_title = get_title_from_hwnd(hWnd);
if (this_title.empty())
return call_next;
wildcard_string lhs(data->title);
const char* rhs = &this_title[0];
if (lhs != rhs)
return call_next;
data->handle = hWnd;
return finished;
}
}
// Returns the window handle when found. if it returns 0 GetLastError() will return more information
// title may contain '*' as wildcard for [0, n] characters
inline handle_t find_window(const char* title)
{
assert(title && "invalid pointer");
detail::find_window_data data(title);
if( EnumWindows(detail::find_window_impl, reinterpret_cast<LPARAM>(&data)) )
{
SetLastError(ERROR_FILE_NOT_FOUND);
return no_handle;
}
SetLastError(ERROR_SUCCESS);
return data.handle;
}
}
struct scoped_foreground
{
using hwnd_t = window::handle_t;
scoped_foreground(hwnd_t handle)
: old_foreground( window::get_foreground_window() )
, new_foreground( handle )
{
assert(new_foreground != window::no_handle && "bad handle");
if( old_foreground != new_foreground )
window::set_foreground_window(new_foreground);
}
~scoped_foreground()
{
if (old_foreground == new_foreground)
return;
window::thread_attacher attacher(old_foreground, new_foreground);
window::set_foreground_window(old_foreground);
}
private:
hwnd_t old_foreground;
hwnd_t new_foreground;
};
#include <iostream>
void real_main()
{
auto notepad_handle = window::find_window("* - Editor");
if(notepad_handle == window::no_handle)
throw std::runtime_error("no window found");
scoped_foreground focus( notepad_handle );
{
{
key_send t1(keys::SHIFT);
key_send t2(keys::H);
}
key_send t3(keys::E);
key_send t4(keys::Y);
}
Sleep(1000); // !
}
int main()
{
try
{
real_main();
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
}
std::cout << "fertig" << std::endl;
char x;
std::cin >> x;
}