AutoHotkey (AHK): GetKeyState not recognizing keypress made by ControlSend - state

I have a very complex script that depresses a key, and needs to check at cerrtain points whether that key is still depressed or not, so GetKeyState seemed perfect, but I could not get it to work, so I made a simple script doing only that, and it still doesn't recognize the state.
The script is as follows:
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
~#Right::
ControlSend,, {d down}, ahk_pid 6920
Loop{
GetKeyState, dState, d
;MsgBox, d Key State: %dState%
SplashTextOn,300,50, AutoNavigatorInfo, d Key State: %dState%
WinMove, AutoNavigatorInfo, , 300, 0 ; Move the splash window to the top left corner.
}
Sadly, the splashText window I use keeps relaying dState as U. Very odd seeing as in the test window I am using, it is interacting properly with the d key depressed.

I agree with blackholyman "GetKeyState will not work for controlsend as GetKeyState Gets the global system state of the key but controlsend only sets the state locally i.e the key state is only set for one control or window."
But if you need "ControlSend for certain window functions, such as sending commandby PID" I think you can do it with Send command too. Use WinActivate to activate window that you need to send key and after use Send to send key. You can use PID with WinActivate command instead of Wintitle parameter, more about it here: http://ahkscript.org/docs/misc/WinTitle.htm
Try this code:
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases.
SendMode Input ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory.
~#Right::
WinActivate, ahk_pid 6920
Send, {d down}
Loop{
GetKeyState, dState, d
;MsgBox, d Key State: %dState%
SplashTextOn,300,50, AutoNavigatorInfo, d Key State: %dState%
WinMove, AutoNavigatorInfo, , 300, 0 ; Move the splash window to the top left corner.
}

GetKeyState will not work for controlsend as GetKeyState Gets the global system state of the key but controlsend only sets the state locally i.e the key state is only set for one control or window.

Related

Crashing when calling QTcpSocket::setSocketDescriptor()

my project using QTcpSocket and the function setSocketDescriptor(). The code is very normal
QTcpSocket *socket = new QTcpSocket();
socket->setSocketDescriptor(this->m_socketDescriptor);
This coding worked fine most of the time until I ran a performance testing on Windows Server 2016, the crash occurred. I debugging with the crash dump, here is the log
0000004f`ad1ff4e0 : ucrtbase!abort+0x4e
00000000`6ed19790 : Qt5Core!qt_logging_to_console+0x15a
000001b7`79015508 : Qt5Core!QMessageLogger::fatal+0x6d
0000004f`ad1ff0f0 : Qt5Core!QEventDispatcherWin32::installMessageHook+0xc0
00000000`00000000 : Qt5Core!QEventDispatcherWin32::createInternalHwnd+0xf3
000001b7`785b0000 : Qt5Core!QEventDispatcherWin32::registerSocketNotifier+0x13e
000001b7`7ad57580 : Qt5Core!QSocketNotifier::QSocketNotifier+0xf9
00000000`00000001 : Qt5Network!QLocalSocket::socketDescriptor+0x4cf7
00000000`00000000 : Qt5Network!QAbstractSocket::setSocketDescriptor+0x256
In the stderr log, I see those logs
CreateWindow() for QEventDispatcherWin32 internal window failed (Not enough storage is available to process this command.)
Qt: INTERNAL ERROR: failed to install GetMessage hook: 8, Not enough storage is available to process this command.
Here is the function, where the code was stopped on the Qt codebase
void QEventDispatcherWin32::installMessageHook()
{
Q_D(QEventDispatcherWin32);
if (d->getMessageHook)
return;
// setup GetMessage hook needed to drive our posted events
d->getMessageHook = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) qt_GetMessageHook, NULL, GetCurrentThreadId());
if (Q_UNLIKELY(!d->getMessageHook)) {
int errorCode = GetLastError();
qFatal("Qt: INTERNAL ERROR: failed to install GetMessage hook: %d, %s",
errorCode, qPrintable(qt_error_string(errorCode)));
}
}
I did research and the error Not enough storage is available to process this command. maybe the OS (Windows) does not have enough resources to process this function (SetWindowsHookEx) and failed to create a hook, and then Qt fire a fatal signal, finally my app is killed.
I tested this on Windows Server 2019, the app is working fine, no crashes appear.
I just want to know more about the meaning of the error message (stderr) cause I don't really know what is "Not enough storage"? I think it is maybe the limit or bug of the Windows Server 2016? If yes, is there any way to overcome this issue on Windows Server 2016?
The error ‘Not enough storage is available to process this command’ usually occurs in Windows servers when the registry value is set incorrectly or after a recent reset or reinstallations, the configurations are not set correctly.
Below is verified procedure for this issue:
Click on Start > Run > regedit & press Enter
Find this key name HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\LanmanServer\Parameters
Locate IRPStackSize
If this value does not exist Right Click on Parameters key and Click on New > Dword Value and type in IRPStackSize under the name.
The name of the value must be exactly (combination of uppercase and lowercase letters) the same as what I have above.
Right Click on the IRPStackSize and click on Modify
Select Decimal enter a value higher than 15(Maximum Value is 50 decimal) and Click Ok
You can close the registry editor and restart your computer.
Reference
After researching for a few days I finally can configure the Windows Server 2016 setting (registry) to prevent the crash.
So basically it is a limitation of the OS itself, it is called desktop heap limitation.
https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/desktop-heap-limitation-out-of-memory
(The funny thing is the error message is Not enough storage is available to process this command but the real problem came to desktop heap limitation. )
So for the solution, flowing the steps in this link: https://learn.microsoft.com/en-us/troubleshoot/system-center/orchestrator/increase-maximum-number-concurrent-policy-instances
I increased the 3rd parameter of SharedSection to 2048 and it fix the issue.
Summary steps:
Desktop Heap for the non-interactive desktops is identified by the third parameter of the SharedSection= segment of the following registry value:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SubSystems\Windows
The default data for this registry value will look something like the following:
%SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,3072,512 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=winsrv:ConServerDllInitialization,2 ProfileControl=Off MaxRequestThreads=16
The value to be entered into the Third Parameter of the SharedSection= segment should be based on the calculation of:
(number of desired concurrent policies) * 10 = (third parameter value)
Example: If it's desired to have 200 concurrent policy instances, then 200 * 10 = 2000, rounding up to a nice memory number gives you 2048as the third parameter resulting in the following update to be made to the registry value:
SharedSection=1024,3072,2048

How to perform a subroutine every 5 seconds?

I have a subroutine to check if a disk is mounted,
I would like to know how do I make this subroutine always run every 5 seconds.
thanks in advance!
on checkMyDiskIsMounted()
tell application "Finder"
activate
if exists disk "myDisk" then
--do anything
else
--do anything
end if
end tell
end checkMyDiskIsMounted
Using things like AppleScript's delay command, a shell utility such as sleep, or even a tight repeat loop should all be avoided, as those tend to block the user interface while they are running.
A repeating timer could be used to periodically poll, but instead of wasting time continually checking for something that may or may not happen, NSWorkspace can be used, as it provides notifications for exactly this kind of thing (amongst others). The way this works is your application registers for the particular notifications that it is interested in, and the specified handler is called when (if) the event occurs.
Note that the following script includes statements so that it can be run from the Script Editor as an example - observers are added to the application instance, and will stick around until they are removed or the application is quit:
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "AppKit"
use scripting additions
on run -- or whatever initialization handler
# set up notifications
tell current application's NSWorkspace's sharedWorkspace's notificationCenter
its addObserver:me selector:"volumeMounted:" |name|:(current application's NSWorkspaceDidMountNotification) object:(missing value)
its addObserver:me selector:"volumeUnmounted:" |name|:(current application's NSWorkspaceDidUnmountNotification) object:(missing value)
end tell
end run
on volumeMounted:aNotification -- do something on mount
set volumeName to (NSWorkspaceVolumeLocalizedNameKey of aNotification's userInfo) as text
display notification "The volume " & quoted form of volumeName & " was mounted." with title "Volume mounted" sound name "Hero" -- or whatever
end volumeMounted:
on volumeUnmounted:aNotification -- do something on unmount
set volumeName to (NSWorkspaceVolumeLocalizedNameKey of aNotification's userInfo) as text
display notification "The volume " & quoted form of volumeName & " was unmounted." with title "Volume unmounted" sound name "Funk" -- or whatever
end volumeUnmounted:
Four options:
A repeat loop with delay as suggested by matt
repeat
-- code
delay 5
end repeat
A (stay open) applet with idle handler
on run
-- do intialiations
end run
on idle
-- code
return 5
end idle
An AppleScriptObjC notification like suggested by red_menace
A launchd agent observing the /Volumes folder
In favor of option 3 and 4 which inexpensively notify about a change the first two options which poll periodically are discouraged.

How do I make your program increment repeatedly until another key is pressed in a switch statement

I have been working on one of those snake games and I have a switch statement that says if a key is pressed to move the snake in a direction by incrementing/decrementing, but it will only do that if I hold it. I am looking for a way to have the snakes location keep incrementing without the user holding that key. I put one case below
if(_kbhit()) {
switch(_getch()) {
case 'a' :
dir = LEFT;
x--;
I am looking for a way to have ... keep incrementing without the user
holding that key."
IMHO, you should consider the "select()" function (if it is available in your OS)
Long ago I used "select()" in vxWorks. I see from a man page this function is also available to Ubuntu Linux. (maybe it is available to your system?)
With the select statement, a thread or program can "monitor multiple file descriptors, waiting until one or more of the file descriptors become "ready" for some class of I/O operation (e.g. input possible). A file descriptor is considered ready if it is possible to perform a corresponding operation (e.g., read() without blocking, or a sufficiently small write())." (from man page)
In practice, the system I worked on had a user interface thread (one of several) issue reads and monitor the input fd (via select) for user input. Our select used a 1/2 second time out (you choose rate). Thus, every half second, if no user input occurred at that port (i.e. device), the time out would release the program to check the bits in the fd_sets.
Nothing prevents the code from doing additional activites in a timeout.
I would guess you will only need to work on readfds, and can leave the other fds empty.
In other words, with select, your code 'monitors' for some user input with a time out, and takes action on either the user input (key stroke) or because of the time out.
This sounds like what you are looking for - action without pressing a key.
Your current design sounds like it moves the snake on press event.
I think you're looking to modify the design such that press events update some current-direction flag, while some background timer thread moves the snake at some regular frame rate.
Your code only moves the snake on key press. You need to implement some kind of game loop which moves the snake at a regular interval based on a direction variable. You can then refactor your key press code to simply update the direction.
Pseudo code:
while: # loop forever
# below could be your switch statement
if direction == 0: # north
y--
if direction == 1: # east
x++
if direction == 2: # south
y++
if direction == 4: # west
x--
if _kbhit():
if _getch() == 'a':
direction == 4 # west
# etc...

Linux - Detecting idleness

I need to detect when a computer is idle for a certain time period. My definition of idleness is:
No users logged in, either by remote methods or on the local machine
X server inactivity, with no movement of mouse or key presses
TTY keyboard inactivity (hopefully)
Since the majority of distros have now moved to logind, I should be able to use its DBUS interface to find out if users are logged in, and also to monitor logins/logouts. I have used xautolock to detect X idleness before, and I could continue using that, but xscreensaver is also available. Preferably however I want to move away from any specific dependencies like the screensaver due to different desktop environments using different components.
Ideally, I would also be able to base idleness on TTY keyboard inactivity, however this isn't my biggest concern. According to this answer, I should be able to directly query the /dev/input/* interfaces, however I have no clue how to go about this.
My previous attempts at making such a monitor have used Bash, due to the ease of changing a plain text script file, howver I am happy using C++ in case more advanced methods are required to accomplish this.
From a purely shell standpoint (since you tagged this bash), you can get really close to what you want.
#!/bin/sh
users_are_logged_in() {
who |grep -q .
return $?
}
x_is_blanked() {
local DISPLAY=:0
if xscreensaver-command -time |grep -q 'screen blanked'; then
return 0 # we found a blanked xscreensaver: return true
fi
# no blanked xscreensaver. Look for DPMS modes
xset -q |awk '
/DPMS is Enabled/ { dpms = 1 } # DPMS is enabled
/Monitor is On$/ { monitor = 1 } # The monitor is on
END { if(dpms && !monitor) { exit 0 } else { exit 1 } }'
return $? # true when DPMS is enabled and the monitor is not on
}
nobody_here() {
! users_are_logged_in && x_is_blanked
return $?
}
if nobody_here; then
sleep 2m
if nobody_here; then
# ...
fi
fi
This assumes that a user can log in in two minutes and that otherwise, there is no TTY keyboard activity.
You should verify that the who |grep works on your system (i.e. no headers). I had originally grepped for / but then it won't work on FreeBSD. If who has headers, maybe try [ $(who |grep -c .) -gt 1 ] which will tell you that the number of lines that who outputs is more than one.
I share your worry about the screensaver part; xscreensaver likely isn't running in the login manager (any other form of X would involve a user logged in, which who would detect), e.g. GDM uses gnome-screensaver, whose syntax would be slightly different. The DPMS part may be good enough, giving a far larger buffer for graphical logins than the two minutes for console login.
Using return $? in the last line of a function is redundant. I used it to clarify that we're actually using the return value from the previous line. nobody_here short circuits, so if no users are logged in, there is no need to run the more expensive check for the status of X.
Side note: Be careful about using the term "idle" as it more typically refers to resource (hardware, that is) consumption (e.g. CPU load). See the uptime command for load averages for the most common way of determining system (resource) idleness. (This is why I named my function nobody_here instead of e.g. is_idle)

How to refresh logon screensaver parameter changes?

I have a Windows service that may change the timeout on the logon screensaver in Windows (as described here.) To do that I change the following registry key to the timeout in seconds:
HKEY_USERS\.DEFAULT\Control Panel\Desktop\ScreenSaveTimeOut
The issue is that how do I make OS "read" or refresh the actual screensaver timeout after a change in the registry key above?
My practice shows that it is refreshed (for sure) only when I reboot the system, but in my case I need it to be applied without the reboot.
EDIT_1: After suggestion below I tried, as it seems to me, all possible combinations of the flags for the following:
DWORD bsmInfo1 = BSM_ALLDESKTOPS;
DWORD dwFlgs = BSF_FORCEIFHUNG | BSF_IGNORECURRENTTASK | BSF_NOTIMEOUTIFNOTHUNG | BSF_SENDNOTIFYMESSAGE;
int nbsm1 = ::BroadcastSystemMessage(dwFlgs, &bsmInfo1, WM_SETTINGCHANGE, 0, (LPARAM)L"Windows");
DWORD bsmInfo2 = BSM_ALLDESKTOPS;
int nbsm2 = ::BroadcastSystemMessage(dwFlgs, &bsmInfo2, WM_SETTINGCHANGE, 0, (LPARAM)L"WindowsThemeElement");
to no avail :( I receive 1 as a result from both calls but it has no effect.
I was able to resolve this.-.-.
If your service is running in the same session as the logon screensaver then you can call SystemParametersInfo with the SPI_SETSCREENSAVETIMEOUT flag.
SystemParametersInfo broadcasts the WM_SETTINGCHANGE message to all top level windows to indicate that a parameter has changed. If your code isn't running in the correct session then you could use BroadcastSystemMessage with the BSM_ALLDESKTOPS flag to deliver the WM_SETTINGCHANGE message. However, this does require the SE_TCB_NAME privilege, so your code would have to be running as SYSTEM.
I haven't actually tried this cross-session, so I can't guarantee that it works.