I setup "polish-programmers" keyboard layout
I try to:
HKL hkl=GetKeyboardLayout(0);
for(unsigned long ch=0x20; ch<=0xff ; ++ch)
{
int v = HIBYTE(VkKeyScanEx(ch,hkl));
if(v==6){
return (GetKeyState(VK_CONTROL) & 0x8000) &&(GetKeyState(VK_RMENU) & 0x8000);
}
}
return false;
I made test with GetKeyboardState - same result: always left control have same flags as right alt(altgr)
May be somebody have workaround?
Related
Does anyone know a good method how we can check from code in C/C++ if the actual keyboard layout has the ALTGR key or not on it?
I think the best method would be to read and interpret the keyboard layout file e.g. "KBDGR.DLL" for german but the API to do this does not exists and that what exists is not well documented.
Is there any other way to do this?
I know it's been a while - This is the best I came up with
BOOL CMonitor::LayoutHasAltGr(HKL keyboard_layout)
{
BOOL hasAltGr = FALSE;
int scancode;
for (WORD i = 32; i < 256; ++i)
{
scancode = VkKeyScanEx((TCHAR)i, keyboard_layout);
if (scancode != -1 && (scancode & 0x600) == 0x600)
{
// Ctrl + Alt means AltGr
hasAltGr = TRUE;
break;
}
}
return hasAltGr;
So, here is a countdown.
My aim is the next: if you don't do anything for the given time (ent_sec) the countdown will reach 0 after a time and return with 0, BUT if you press down the letter c (code: 99) the countdown stops and you can enter your PIN code and return with it.
I have already solved the problem with Windows.h in the next way:
if (GetAsyncKeyState(VK_SPACE))
This solves the problem is through WIN32 API (in this case you have to press SPACE, not letter 'c'), but it revealed that I can't use any WinAPI function (school project). So I rewrite this line to the following:
if (getchar() == 99)
But unfortunately it doesn't work in the proper way, cause my countdown stops in almost every second until I dont't press some "wrong" key (for example I press 'x', then the countdown goes forward, but in the next sec it stops again)... In the first solution (win func) this problem doesn't exist... So how can I fix that? Thanks. Here is the whole code of my function:
unsigned Timer::DownCount
{
int ent_sec = this.time;
cout << "The counter has started (" << this.time << "sec), press 'C' to enter your PIN code: " << endl;
while (ent_sec >= 0)
{
if (getchar() == 99) // c letter's code is 99 in ANSI (or ASCII dunno)
{
unsigned code;
cout << "PIN code: ";
cin >> code;
return code;
}
else
{
SecCounter(1); // this function counts 1 secundum
cout << ent_sec << endl;
ent_sec--;
}
}
return 0;
}
I don't believe there's a standard way to do this that will work across all platforms, but here's one way of doing it that will work on Windows without actually using Windows API functions.
int getch_nowait()
{
if (!kbhit()) return -1;
return getch();
}
Then your check just becomes if (getch_nowait() == 99) ...
This code may be compiler specific. If it doesn't work for you, it'll help if you tell us what compiler and operating system you are using.
const char IsPressed = 1; // 1
const char WasHeldDown = 2; // 10
const char IsFirstPress = 4; // 100
char* keystates[256];
Class::CalculateKeyStates()
{
for(int i = 0; i < 256; ++i)
{
if(this->IsDown(i))
{
keystates[i] |= IsPressed; // turn on
if(keystates[i] & WasHeldDown)
{
//keystates[i] |= IsFirstPress;
keystates[i] &= ~IsFirstPress; // turn off
}
else
{
keystates[i] |= WasHeldDown + IsFirstPress; // Turn on
}
}
else
{
keystates[i] = 0; // Turn ALL off
}
}
}
This function would be a member function of a class, Class. The other member function, IsDown, will return a true if the key in question is down and false if not.
Can you see any way of further improving this function?
Thanks
EDIT:
I will expand a bit as to what is done why. This is a modification of an bit of code that works through an array keyStates (which was a struct of three bools) setting IsPressed to false for all of the keys. then again setting Ispressed to the value of this->IsDown and then a third time looping through checking if the key had been held, if it has then its no longer the first press so set that to false. if it was not held down, then set first press to true and was held to true as well, so next time it is flagged as having been held.
EDIT2:
Added some comments to code and corrected one line
Personally, I would define the key-states as disjoint states and write a simple state-machine, thus:
enum keystate
{
inactive,
firstPress,
active
};
keystate keystates[256];
Class::CalculateKeyStates()
{
for (int i = 0; i < 256; ++i)
{
keystate &k = keystates[i];
switch (k)
{
inactive:
k = (isDown(i)) ? firstPress : inactive;
break;
firstPress:
k = (isDown(i)) ? active : inactive;
break;
active:
k = (isDown(i)) ? active : inactive;
break;
}
}
}
This is easier to extend, and easier to read if it gets any more complex.
You are always setting IsFirstPress if the key is down, which might not be what you want.
I'm not sure what you want to achieve with IsFirstPress, as the keystate cannot remember any previous presses anyways. If you want to mark with this bit, that it's the first time you recognized the key being down, then your logic is wrong in the corresponding if statement.
keystates[i] & WasHeldDown evaluates to true if you already set the bit WasHeldDown earlier for this keystate.
In that case, what you may want to do is actually remove the IsFirstPress bit by xor-ing it: keystates[i] ^= IsFirstPress
I have a list of items (potentially large) from which the user must select one. I'd like to allow the user to type the first few letters of the desired item to jump to the correct place in the list. By default, each keypress jumps to the first item starting with that letter, so you can't type the first several letters. Is there any straightforward way to do this? Any CodeProject or other such example?
I've looked for hours, and found any number of samples for IAutocomplete, but that won't help here because I need to guarantee that the result is in the list.
The only way I can think to do this is to derive from CListBox, capture the keystrokes myself, find the item, run a timer so that new keystrokes after a sufficient pause will start a new search... since I'm not an MFC jock, this is daunting. Any tips much appreciated.
One clarifying note: my ultimate goal is actually to get this keyboard behavior for a ComboBox of DropDownList style (i.e. no edit box). The lack of an edit box rules out most autocomplete code, and the need for ComboBox functionality means I can't use CListCtrl by itself.
After much unnecessary pain, I've discovered that the real correct answer is simply to use LBS_SORT. Simply by specifying this style, the basic vanilla listbox supports the incremental search keyboard shortcut style I wanted. Without LBS_SORT (or CBS_SORT for a combobox), you get the irritating and almost-useless jump-to-first-letter-only behavior. I didn't try LBS_SORT because my list contents were added in sorted order anyway.
So the dozen or so hours of investigating custom controls, etc., all for naught because the Microsoft documentation makes no mention of this important behavioral difference in the description of LBS_SORT!!
Thanks to everyone who contributed.
I've implemented such a functionality in core Win32. Heres the code.
Somewhere in your message loop that processes the list box insert:
switch(message)
{
case WM_CHAR:
if(HandleListBoxKeyStrokes(hwnd, wParam) == FALSE)
return FALSE;
....
Heres the code (propably not fully complete):
/* ======================================================================== */
/* ======================================================================== */
#define RETURNr(a, b) // homegrown asserts
BOOLEAN HandleListBoxKeyStrokes(HWND hwnd, UINT theKey)
{
#define MAXCHARCACHEINTERVALL 600.0 // Max. milisecs time offset to consider as typed 'at once'
static char sgLastChars[255] = {'0'};
static double sgLastCharTime = 0.;
static HWND sgLasthwnd = NULL;
if(GetSecs() - sgLastCharTime > MAXCHARCACHEINTERVALL ||
sgLasthwnd != hwnd)
*sgLastChars = 0;
if(theKey == ' ' && *sgLastChars == 0)
return TRUE;
sgLastCharTime = GetSecs();
sgLasthwnd = hwnd;
AppendChar(sgLastChars, toupper(theKey));
if(strlen(sgLastChars) > 1)
{
LONG l = GetWindowLong(hwnd, GWL_STYLE);
Char255 tx;
GetClassName(hwnd, tx, sizeof(tx));
if( (! stricmp(tx, "Listbox") &&
! (l & (LBS_EXTENDEDSEL | LBS_MULTIPLESEL)) ) ||
(! stricmp(tx, "ComboBox") && // combo Box support
l & CBS_DROPDOWNLIST &&
! (l & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) ) )
{
long Count, l, BestMatch = - 1, BestMatchOff = 0;
long LBcmdSet[] = {LB_GETCOUNT, LB_GETTEXTLEN , LB_GETTEXT};
long CBcmdSet[] = {CB_GETCOUNT, CB_GETLBTEXTLEN, CB_GETLBTEXT};
long *cmdSet = (! stricmp(tx, "ComboBox")) ? CBcmdSet : LBcmdSet;
RETURNr((Count = SendMessage(hwnd, cmdSet[0], 0, 0)) != LB_ERR, 0);
for(int i = 0; i < Count; i++)
{
RETURNr((l = SendMessage(hwnd, cmdSet[1], i, 0)) != LB_ERR, TRUE);
RETURNr( l < sizeof(tx), TRUE);
RETURNr((l = SendMessage(hwnd, cmdSet[2], i, (LPARAM)&tx)) != LB_ERR, TRUE);
strupr(tx);
if(! strncmp(tx, sgLastChars, strlen(sgLastChars)))
{
SelListBoxAndNotify(hwnd, i);
return FALSE;
}
char *p;
if(p = strstr(tx, sgLastChars))
{
int off = p - tx;
if(BestMatch == -1 || off < BestMatchOff)
{
BestMatch = i;
BestMatchOff = off;
}
}
}
// If text not found at start of string see if it matches some part inside the string
if(BestMatch != -1)
SelListBoxAndNotify(hwnd, BestMatch);
// Nothing found - dont process
return FALSE;
}
}
return TRUE;
}
/* ======================================================================== */
/* ======================================================================== */
void SelListBoxAndNotify(HWND hwnd, int index)
{
// i am sorry here - this is some XVT-toolkit specific code.
// it has to be replaced with something similar for native Win32
WINDOW win = xvtwi_hwnd_to_window(hwnd);
WINDOW parent = xvt_vobj_get_parent(win);
xvt_list_set_sel(win, index, 1);
EVENT evt;
memset(&evt, 0, sizeof(evt));
evt.type = E_CONTROL;
evt.v.ctl.id = GetDlgCtrlID(hwnd);
evt.v.ctl.ci.v.lbox.dbl_click = FALSE;
xvt_win_dispatch_event(parent, &evt);
}
/* ======================================================================== */
/* ======================================================================== */
double GetSecs(void)
{
struct timeb timebuffer;
ftime(&timebuffer);
return (double)timebuffer.millitm +
((double)timebuffer.time * 1000.) - // Timezone needed for DbfGetToday
((double)timebuffer.timezone * 60. * 1000.);
}
/* ======================================================================== */
/* ======================================================================== */
char AppendChar(char *tx, char C)
{ int i;
i = strlen(tx);
tx[i ] = C;
tx[i + 1] = 0;
return(C);
}
Can you use a CListView CListCtrl instead? They work like that by default.
Visual Studio gives many navigation hotkeys:
F8 for next item in current panel (search results, errors ...),
Control+K, N for bookmarks,
Alt+- for going back and more.
There is one hotkey that I can't find, and I can't even find the menu-command for it, so I can't create the hotkey myself.
I don't know if such exist: Previous and Next call-stack frame.
I try not using the mouse when programming, but when I need to go back the stack, I must use it to double click the previous frame.
Anyone? How about a macro that does it?
I wrote 2 macros to gain it: PreviousStackFrame and NextStackFrame and assigned shortcuts to
Function StackFrameIndex(ByRef aFrames As EnvDTE.StackFrames, ByRef aFrame As EnvDTE.StackFrame) As Long
For StackFrameIndex = 1 To aFrames.Count
If aFrames.Item(StackFrameIndex) Is aFrame Then Exit Function
Next
StackFrameIndex = -1
End Function
Sub NavigateStack(ByVal aShift As Long)
If DTE.Debugger.CurrentProgram Is Nothing Then
DTE.StatusBar.Text = "No program is currently being debugged."
Exit Sub
End If
Dim ind As Long = StackFrameIndex(DTE.Debugger.CurrentThread.StackFrames, DTE.Debugger.CurrentStackFrame)
If ind = -1 Then
DTE.StatusBar.Text = "Stack navigation failed"
Exit Sub
End If
ind = ind + aShift
If ind <= 0 Or ind > DTE.Debugger.CurrentThread.StackFrames.Count Then
DTE.StatusBar.Text = "Stack frame index is out of range"
Exit Sub
End If
DTE.Debugger.CurrentStackFrame = DTE.Debugger.CurrentThread.StackFrames.Item(ind)
DTE.StatusBar.Text = "Stack frame index: " & ind & " of " & DTE.Debugger.CurrentThread.StackFrames.Count
End Sub
Sub PreviousStackFrame()
NavigateStack(1)
End Sub
Sub NextStackFrame()
NavigateStack(-1)
End Sub
I have solved this problem with AutoHotkey. I made this a few months ago.
Suppose you wanted to use Control+1 and Control+2 and that Control+Alt+C is bound to showing the Call Stack window:
^1::SendInput !^c{down}{enter}
^2::SendInput !^c{up}{enter}
It seems to work pretty well. If you aren't already using AutoHotkey to show Visual Studio who's boss, please give it a shot. Your question indicates that you would benefit greatly from it. It's a game changer. Good luck.
I don't think theres an explict next-frame / prev-frame key binding but heres what I do.
CTRL-ALT-C is already bound to "Debug.CallStack"
This will focus you in the Call Stack Tool Window
Once focused in the Callstack window... Up & Down arrows will move you through the call stack frames
I've then bound
CTRL-C, CTRL-S to "DebuggerContextMenus.CallStackWindow.SwitchToFrame"
and
CTRL-C, CTRL-C to "DebuggerContextMenus.CallStackWindow.SwitchToCode"
both of which will take you back into the code window at the particular frame.
Hope that helps.
Huge thanks to #Oleg Svechkarenko for his answer that gave me a starting point in crafting this solution. Since modern versions of Visual Studio no longer have official macro support, this should drop in for those who use the Visual Commander plugin, but probably can be easily adapted for any other macro extension.
Here is the code for the command, I created one for navigating up the call stack and one for navigating down with the same code except the parameter passed to MoveStackIndex(), then bound keyboard shortcuts to them:
using EnvDTE;
using EnvDTE80;
using System;
public class C : VisualCommanderExt.ICommand
{
enum MoveDirection
{
Up,
Down,
}
private bool IsValidFrame(StackFrame frame)
{
string language = frame.Language;
bool result = (language == "C#" ||
language == "C++" ||
language == "VB" ||
language == "Python");
return result;
}
private void MoveStackIndex(EnvDTE80.DTE2 DTE, MoveDirection direction)
{
StackFrame currentFrame = DTE.Debugger.CurrentStackFrame;
bool foundTarget = false;
bool pastCurrent = false;
StackFrame lastValid = null;
foreach (StackFrame frame in DTE.Debugger.CurrentThread.StackFrames)
{
bool isCurrent = frame == currentFrame;
if (direction == MoveDirection.Down)
{
if (isCurrent)
{
if (lastValid == null)
{
// No valid frames below this one
break;
}
else
{
DTE.Debugger.CurrentStackFrame = lastValid;
foundTarget = true;
break;
}
}
else
{
if (IsValidFrame(frame))
{
lastValid = frame;
}
}
}
if (direction == MoveDirection.Up && pastCurrent)
{
if (IsValidFrame(frame))
{
DTE.Debugger.CurrentStackFrame = frame;
foundTarget = true;
break;
}
}
if (isCurrent)
{
pastCurrent = true;
}
}
if (!foundTarget)
{
DTE.StatusBar.Text = "Failed to find valid stack frame in that direction.";
}
}
public void Run(EnvDTE80.DTE2 DTE, Microsoft.VisualStudio.Shell.Package package)
{
if (DTE.Debugger.CurrentProgram == null)
{
DTE.StatusBar.Text = "Debug session not active.";
}
else
{
// NOTE: Change param 2 to MoveDirection.Up for the up command
MoveStackIndex(DTE, MoveDirection.Down);
}
}
}
Look in Tools->Options->Environment->Keyboard. Enter "stack" or "frame" and related menus will appear. It seems that there's no next and previous call-stack frame.