I am trying to remove windows error sound from my Flutter (Win32) Application. After some research I came up with this fix. I tried this fix but it's not helping in my Flutter application.
Heres the code to handle WM_SYSCHAR message:
LRESULT CALLBACK Win32Window::WndProc(HWND const window,
UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept {
if (message == WM_SYSCHAR) {
std::cout << "SYSCHAR from win32" << std::endl;
return 0;
}
...
}
When I press the Alt+Space, "SYSCHAR from win32" is printed in the console. But whenever I press any other key with Alt, this is not printed and the Windows error sound is played. It seems like SYSCHAR message is handled somewhere else?
This can be used to know the working and initialization of Win32 App in Flutter.
I just want to tell the Application that Alt+Key combinations are handled and it doesn't have to play Windows error sound.
Thanks to #IInspectable for suggesting me to use keyboard accelerators.
The problem is Flutter's main loop doesn't have keyboard accelerators. So I followed how to use keyboard accelerators documentation and modified the main loop as follows:
Created accelerator table by calling CreateAcceleratorTable
LPACCEL accels = GenerateAccels();
HACCEL haccel = CreateAcceleratorTable(accels, 36);
if (haccel==NULL) {
return EXIT_FAILURE;
}
Here's the GenerateAccels function:
LPACCEL GenerateAccels() {
LPACCEL lpAccel = new ACCEL[36];
// Alt + Number combinations:
for (int i = 0; i < 10; i++) {
lpAccel[i].fVirt = FALT;
lpAccel[i].key = (WORD)(0x30 + i);
}
// Alt + Alphabet combinations (NOT WORKING AT THE MOMENT):
for (int i = 0; i < 26; i++) {
lpAccel[i + 10].fVirt = FALT;
lpAccel[i + 10].key = (WORD)(0x41 + i);
}
return lpAccel;
}
Then adding a call to TranslateAccelerator in the main loop
::MSG msg = { };
while (::GetMessage(&msg, nullptr, 0, 0) > 0) {
if (!TranslateAccelerator(msg.hwnd, haccel, &msg)) {
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
I also added this check to prevent error sound from playing when any key is pressed after pressing Alt (Alt is not held down).
flutter_window.cpp
case WM_SYSCOMMAND:
// If the selection is in menu
// handle the key event
// This prevents the error/beep sound
if (wparam == SC_KEYMENU) {
return 0;
}
Note: One thing that isn't working is Alt + Alphabet combinations. When pressed, it is still playing that error sound. In my case it's not important right now, but if someone finds the fix then please share.
Related
I need a function in a game loop that should only return true on first press.
I don't know which game I can give an example from which game is currently on the market, but I will explain this request in detail (I haven't played/can't play any of the modern games because I'm blind).
For example, there is an event you are listening to in the loop. When the user presses the S key, a text showing the last status of the character appears on the screen: Stamina, energy etc.
This loop can run thousands of times per second, as the loops depend on the speed of the hardware and the code you write.
We only need to detect the first press of the user. It should return false when the key is hold pressed. Otherwise, the last status of the user is shown thousands of times on the screen.
I am trying to provide this functionality using win32api. GetAsyncKeyState seems like the right option for this scenario but I don't understand how this can be done.
bool IsPressed(int key) {
return GetAsyncKeyState(key) & 1 != 0;
}
The function I wrote acts like a char event.
How can I write this?
I tried using other answers on StackOwerflow. However, I could not find an answer to the question I asked. Still, these answers helped me with some issues:
What is the fastest way to determine a key press and key holding in Win32?
While the GetAsyncKeyState can indicate via least significant bit whether the key has been pressed since the last call to this function, this behavior cannot be relied on.
If the most significant bit is set, the key is down, and if the least significant bit is set, the key was pressed after the previous call to GetAsyncKeyState. However, you should not rely on this last behavior...
Although the least significant bit of the return value indicates whether the key has been pressed since the last query, due to the preemptive multitasking nature of Windows, another application can call GetAsyncKeyState and receive the "recently pressed" bit instead of your application.
Therefore, you can't rely on the Windows API to do the bookkeeping for you. I suggest wrapping any key queries in a class that you'll use for any button presses.
class KeyInput {
public:
using key_type = int;
enum class Transition {
none,
pressed,
released,
};
struct PressResult {
bool pressed;
Transition transition;
};
PressResult state(key_type key) {
PressResult result;
result.pressed = (GetAsyncKeyState(key) < 0);
if (auto it = last_states_.find(key); it != last_states_.end()) {
if (last_states_[key] == result.pressed) {
result.transition = Transition::none;
}
else if (result.pressed) {
result.transition = Transition::pressed;
}
else {
result.transition = Transition::released;
}
}
else {
result.transition = Transition::none;
}
last_states_[key] = result.pressed;
return result;
};
private:
std::unordered_map<key_type, bool> last_states_{};
};
See it in action
Note
This will not capture transitions since the last iteration of your program. In order to handle that, you'll need your class to check every button press (that you care about) on every iteration.
After working on it a more, I realized that I cannot do this with GetAsyncKeyState or a similar function. I wrote something simple using Windows' callback and event system.
I didn't care about data race and other issues. You probably need to use a mutex but that depends on your code.
The code below keeps the state of the keys in an array. Changes are sent to the array with a function by the callback.
If you compile the program in console mode, you will see that it is printed to the console only once when you press A. It was exactly what I was looking for.
To compile you can use:
g++ minimal.cpp
You can press a to test it on a standard querty keyboard.
#include <iostream>
#include <windows.h>
#include <vector>
// We define a struct that holds the key state.
// firstPress will be updated by IsPressed.
struct keyState {
bool firstPress;
bool down;
};
// We have an Array-based collection of keys. Changes will be made by callback.
std::vector<keyState> allKeyStates(256);
void keyProcess(unsigned short key, bool down)
{
if(down) {
if(!allKeyStates[key].down) {
allKeyStates[key].down = true;
allKeyStates[key].firstPress = true;
}
return;
}
allKeyStates[key].down = false;
allKeyStates[key].firstPress = false;
}
bool IsPressed(unsigned short key)
{
if(allKeyStates[key].firstPress) {
allKeyStates[key].firstPress = false;
return true;
}
return false;
}
// forward decleration
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int main()
{
MSG msg = {0};
HWND handle;
WNDCLASS wc = {0};
wc.lpfnWndProc = WndProc;
wc.hInstance = GetModuleHandle(NULL);
wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND);
wc.lpszClassName = "mini_windows_test";
if( !RegisterClass(&wc) )
return -1;
handle = CreateWindow(wc.lpszClassName, "Minimal Key handling application", WS_OVERLAPPEDWINDOW|WS_VISIBLE, 0,0, 640, 480, 0, 0, GetModuleHandle(NULL), NULL);
if(handle == NULL)
return -1;
while(GetMessage(&msg, NULL, 0, 0 ) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
if(IsPressed(0x41)) {
std::cout << "Key A: it will only be print on the first press. Holding the key will not run repeatedly.\n";
}
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message) {
case WM_KEYDOWN:
keyProcess((unsigned short)wParam, true);
break;
case WM_KEYUP:
keyProcess((unsigned short)wParam, false);
break;
case WM_CLOSE:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Apologize for the bady English and typos. You can edit my question and my answer if it works for you.
I do not know about C ++, but it certainly follows the same process in all languages, so you can set that pressure method to "if" and define a number that, by pressing its value, becomes one, And write. In "If" if the value of the number is equal to 1, do not do this again
In java, for example, it says:
int x = 0;
Button back = findViewById(R.id.button);
if(x == 0){
back.setOnClickListener(v -> {
//your code to do;
x = 1;
});
}else{}
that work in C++ too,
I am learning MFC and I am trying to learn about sending messages. I have been searching for days but haven't been able to figure out what exactly it is i need.
I have two dialogue boxes and one of them has a button that is supposed to minimize or restore the other window. I have been able to figure out how to use pointers to accomplish this but i would like to convert it to a SendMessage function.
Here is the current code i use with pointers...
Window2.cpp
void CWindow2::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
if (m_windowOne != NULL) {
if (buttonstate == 0) {
m_windowOne->ShowWindow(SW_MINIMIZE);
buttonstate = 1;
}
else {
m_windowOne->ShowWindow(SW_RESTORE);
buttonstate = 0;
}
}
}
If someone could explain how to get similar function by using messages instead of pointers that would be greatly appreciated.
This is a slightly different context but it conveys the priniples:
void CSomeDialog::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0x0000FFF0) == SC_MINIMIZE)
{
// Minimizing, post to main dialogue also.
AfxGetMainWnd()->ShowWindow(SW_MINIMIZE);
}
else if ((nID & 0x0000FFF0) == SC_RESTORE && IsIconic())
{
// Restoring, post to main dialogue also.
AfxGetMainWnd()->ShowWindow(SW_RESTORE);
}
CDialogEx::OnSysCommand(nID, lParam);
}
In the above scenario, whenever dialog CSomeDialog is minimized or restored it feeds this to the main application window too.
If you have the dialog in question as a variable in your class then ShowWindow(...) should be sufficient.
I am trying to detect in my application, if the Enter/Return buttons are pressed. My problem is that the LVN_KEYDOWN event (Indicates that a key has been pressed) does not detect the Enter/Return key.
I have seen similar questions for other languages, but can not find a solution for C++.
My event to read the key press is:
void ListOption::OnLvnKeydownList1(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLVKEYDOWN pLVKeyDow = reinterpret_cast<LPNMLVKEYDOWN>(pNMHDR);
// TODO: Add your control notification handler code here
if(pLVKeyDow->wVKey == VK_RETURN)
{
OnItemActivateList1(pNMHDR, pResult);
*pResult = 1;
}
*pResult = 0;
}
This code works for almost any key, execept for the Enter key.
My dialog has only one button, and it's "Default Button" value is FALSE. How is it possible to detect the keypress?
Update: My application uses modal dialogs.. It contains a CImageSheet that contains CImagePages(tabs). Here is an image to explain better (I have placed grey blocks to hide some private data).
When I press Enter, I wish to open a new dialog to change the option. Currently this is done with the LVN_ITEMCTIVATE event (when the user double clicks an item):
You can override PreTranslateMessage in the window which owns the ListView. In this case it seems to be a CPropertyPage.
BOOL CMyPropertyPage::PreTranslateMessage(MSG* pMsg)
{
//optional: you can handle keys only when ListView has focus
if (GetFocus() == &List)
if (pMsg->message == WM_KEYDOWN)
{
if (pMsg->wParam == VK_RETURN)
{
//return 1 to eat the message, or allow for default processing
int sel = List.GetNextItem(-1, LVNI_SELECTED);
if (sel >= 0)
{
MessageBox("VK_RETURN");
TRACE("ListView_GetNextItem %d\n", sel);
return 1;
}
else
TRACE("ListView_GetNextItem not-selected, %d\n", sel);
}
if (pMsg->wParam == VK_ESCAPE)
{
//do nothing!
}
}
return CPropertyPage::PreTranslateMessage(pMsg);
}
I've done a lot of searching around with no real solution (to my own problem) so I thought I'd ask here.
I'm designing a kiosk-like program that prevents the user from using task keys (alt+tab, alt+esc, ctrl+esc, etc) while the program is running. Note I'm a novice programmer thus I'd want to stay away from separate dll handling if I can. Particularly, I have went to this site http://support.microsoft.com/kb/226359/en-us for the code. A simplified part of my code looks like this at the top:
HHOOK mule;
HHOOK g_hKeyboardHook;
BOOL g_bFullscreen;
LRESULT CALLBACK LowLevelKeyboardProc (INT nCode, WPARAM wParam, LPARAM lParam)
{
// By returning a non-zero value from the hook procedure, the
// message does not get passed to the target window
KBDLLHOOKSTRUCT *pkbhs = (KBDLLHOOKSTRUCT *) lParam;
BOOL bControlKeyDown = 0;
switch (nCode)
{
case HC_ACTION:
{
// Check to see if the CTRL key is pressed
bControlKeyDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1);
// Disable CTRL+ESC
if (pkbhs->vkCode == VK_ESCAPE && bControlKeyDown)
return 1;
// Disable ALT+TAB
if (pkbhs->vkCode == VK_TAB && pkbhs->flags & LLKHF_ALTDOWN)
return 1;
// Disable ALT+ESC
if (pkbhs->vkCode == VK_ESCAPE && pkbhs->flags & LLKHF_ALTDOWN)
return 1;
break;
}
default:
break;
}
return CallNextHookEx (mule, nCode, wParam, lParam);
}
The my main is
int main(int argc, char **argv)
{
_getch();
g_hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 );
cout << "Testing task keys disabling (alt tab, ctrl esc, alt esc) and taskbar..." << endl;
_getch();
UnhookWindowsHookEx( g_hKeyboardHook );
cout << "Re enabled" << endl;
_getch();
return 0;
}
I realize this code is for really old windows OS, but I've looked around and the other solutions resemble this code so I thought it should work.
But for some reason it doesn't seem to be working. Whenever my program gets to that line of code, the program stalls for like 5 seconds and continues to run, but the task keys are still working.
I've heard that I should be implementing that function as a dll instead of putting everything in one file, but I'm not sure if they're absolutely right (also I know nothing of dlls)
In addition, I've also tried code (to disable windows key) here: http://msdn.microsoft.com/en-us/library/windows/desktop/ee416808(v=vs.85).aspx and it does the same thing my own program (stalls and does nothing)
Can anyone spot where I did something wrong? I'm using VC++ 2010 on windows 7 64bit.
Your code is fine, hooks just doesn't work with console application because windows can't callback into a console application, it requires a message loop.
Read this answer by Hans Passant which applies here too.
I have these links with code:
WMMouseWheel not working in Delphi
How to disable MouseWheel if mouse is not over VirtualTreeView (TVirtualStringTree)
Translated it to C++ Builder but it doesn't work:
UPDATE: After narrowing the problem down it appears that WM_MOUSEWHEEL messages don't work over unfocused TVirtualStringTree control only, they work over other controls. When focus is on e.g. TMemo control, other TMemo control scrolls on wheel but not TVirtualStringTree control. When focus is on TVirtualStringTree it scrolls TVirtualStringTree but not other controls. So the problem is now specific to TVirtualStringTree only.
void __fastcall TForm1::ApplicationEventsMessage(tagMSG &Msg, bool &Handled)
{
TPoint Pt;
HWND Wnd;
if (Msg.message == WM_MOUSEWHEEL ||
Msg.message == WM_VSCROLL ||
Msg.message == WM_HSCROLL)
{
if (GetCursorPos(&Pt))
{
Wnd = WindowFromPoint(Pt);
// It must be a VCL control otherwise we could get access violations
if (IsWindowEnabled(Wnd) && FindControl(Wnd) != NULL)
{
Msg.hwnd = Wnd; // change the message receiver to the control under the cursor
}
}
}
}
Different version of the similar code, also doesn't work:
TPoint pnt;
TWinControl *ctrl;
if ((Msg.message == WM_MOUSEWHEEL ||
Msg.message == WM_VSCROLL ||
Msg.message == WM_HSCROLL) &&
GetCursorPos(&pnt))
{
ctrl = FindVCLWindow(pnt);
if (ctrl != NULL)
{
SendMessage(ctrl->Handle, Msg.message, Msg.wParam, Msg.lParam); // No effect
// SendMessage(ctrl->Handle, WM_VSCROLL, 1, 0); // This is the only thing that actually moves scrollbars but this is not exactly the same message like above
// Msg.hwnd = ctrl->Handle; // No effect
this->Caption=ctrl->Name; // This shows correct control name so the message IS GETTING THROUGH!
Handled = true;
}
}
It should work but it doesn't. Tried other code as well. No effect - mouse wheel does not operate on unfocused control. As you can see, I checked for all 3 variants of wheel messages, it gets correct control under the mouse, it shows that control name but the control doesn't receive wheel messages.
Any ideas what piece of the puzzle am I missing to get it to work?
As nobody offered any proper solution, I am posting my own. The solution is not perfect but at least it does what it needs to do - mouse wheel scrolls all controls under it, including the VirtualTreeView controls. The code in solution is in C++ but Delphi version is very similar (it only needs to be translated).
My current solution is to grab WM_MOUSEWHEEL events and translate them into WM_VSCROLL or WM_HSCROLL to which VirtualTreeView reacts and scrolls the content. Additionally, it needs to take into account high-precision mouse wheels which can have smaller value than WHEEL_DELTA (which is set to 120). Finally, it needs to take into account user setting for number of lines to scroll (set in Control Panel in Windows). So here goes:
Put a TApplicationEvents to a form and in the OnMessage event do this:
void __fastcall TFormMain::ApplicationEventsMessage(tagMSG &Msg, bool &Handled)
{
// Check these 3 messages because some mouse drivers may use VSCROLL instead of MOUSESWHEEL message
if (Msg.message == WM_MOUSEWHEEL || Msg.message == WM_VSCROLL || Msg.message == WM_HSCROLL)
{
TPoint pnt;
TWinControl *ctrl;
if (!GetCursorPos(&pnt)) return;
ctrl = FindVCLWindow(pnt);
if (ctrl != NULL)
{
// ToDo: implement if user needs wheel-click - then we also need KEYSTATE but for this example it is not needed
// int fwKeys = GET_KEYSTATE_WPARAM(Msg.wParam);
int zDelta = GET_WHEEL_DELTA_WPARAM(Msg.wParam),
pvParam = 3; // Windows default value
unsigned MyMsg = WM_VSCROLL;
// ToDo: extract SystemParametersInfo somewhere else so it is not extracted for each WM_MOUSEWHEEL message which may not be needed
switch (Msg.message)
{
// This will translate WM_MOUSEWHEEL into WM_VSCROLL
case WM_MOUSEWHEEL:
case WM_VSCROLL:
// Windows setting which determines how many lines to scroll - we'll send that many WM_VSCROLL or WM_HSCROLL messages
SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &pvParam, 0);
MyMsg = WM_VSCROLL;
break;
case WM_HSCROLL:
// Same as above but for WM_HSCROLL (horizontal wheel)
SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &pvParam, 0);
MyMsg = WM_HSCROLL;
break;
}
// This calculation takes into account high-precision wheels with delta smaller than 120
// Possible TODO: Round up values smaller than 1 (e.g. 0.75 * pvParam) if pvParam is 1
int ScrollBy = ((double)zDelta / (double)WHEEL_DELTA) * pvParam;
// Send multiple messages based on how much the zDelta value was
if (zDelta > 0)
{
do
{
SendMessage(ctrl->Handle, MyMsg, SB_LINEUP, 0);
}
while (--ScrollBy > 0);
}
else
{
do
{
SendMessage(ctrl->Handle, MyMsg, SB_LINEDOWN, 0);
}
while (++ScrollBy < 0);
}
Handled = true;
}
}
}