I'm working on a WinUI 3 - C++/winRT - desktop application.
The application displays and updates in a window-sized XAML SwapChainPanel through Direct2D and needs to receive keyboard input from the user. With KeyDown and KeyUp on the SwapChainPanel, I can get raw keyboard input. However, this provides only VirtualKeys, ScanCodes, RepeatCount, etc. through the accompanying KeyRoutedEventArgs.
I can find no way to tell WinUI 3 which keyboard layout to use, nor any sort of keyboard management for such things as shift keys, etc (VirtualKeys are only capital ASCII letters).
What I've managed to do is build window messages from the KeyDowns and KeyUps and send them to TranslateMessage then DispatchMessage so they end up as WM_CHARs in the window's message loop.
This takes care of quite a bit of the shift, caps lock, etc. logic and produces Unicode. However, it doesn't take into account the keyboard layout which, in my case, is Canadian Multilingual with four layers of characters on most keys. I can receive some non-ASCII characters (Latin 1) but they aren't the right ones.
This must be a common situation with all the different languages in the world, but I haven't found anything in the way of a keyboard processing function that would receive raw information from the keyboard, process the control keys and output Unicode.
If the window's message pump is the only way to go (for now ?), how to get TranslateMessage to take into account the keyboard layout ?
Thanks for any help with this.
I would like to add certain behavior to my program that binds a function to the numpad enter key, if it is present, or bind an alternate key if it is not.
According to Microsoft:
The scan code is the value that the keyboard hardware generates when
the user presses a key. It is a device-dependent value that identifies
the key pressed, as opposed to the character represented by the key.
An application typically ignores scan codes. Instead, it uses the
device-independent virtual-key codes to interpret keystroke messages.
(source)
I know that on my keyboard it is 0x9C (156), but this is not guaranteed to hold true for all keyboards.
I can't use MapVirtualKey() with VK_RETURN and MAPVK_VK_TO_VSC as this always returns the scan code for the primary return key in the center of the keyboard.
How can I obtain this information without any intervention on the part of the user?
My language is C/C++ and this is for Win32 only.
The scan code depends on the hardware, it might not be the same on a different system. There can be more than one scan code that maps to a virtual key. Virtual keys are supposed to be somewhat generic and not tied to the hardware.
You can tell the difference in WM_KEYDOWN and WM_KEYUP; WPARAM is VK_RETURN and bit 24 is set in LPARAM when the Enter key on the numpad is used:
Indicates whether the key is an extended key, such as the right-hand ALT and CTRL keys that appear on an enhanced 101- or 102-key keyboard. The value is 1 if it is an extended key; otherwise, it is 0.
GetKeyboardType can tell you some information about "the keyboard" but since there can be more than one keyboard connected these days you would have to go deeper to find out if there are any keyboards that have the properties you are looking for. Perhaps the SetupAPI knows.
For Numpad Enter to be recognized as either kind of Enter, the keyboard hardware must send a scan code that maps to VK_RETURN within the current keyboard layout. Keyboard layout is determined by system settings and the window which is receiving keyboard input (or the user), not by the physical keyboard. It is quite possible that the virtual keyboard layout does not match the physical keyboard (i.e. the labels on the keys don't match their functions).
There are two strategies for allowing different physical keyboard layouts to function correctly:
Change the labels visible on the keys but keep the scan codes in the same physical positions. For the function of each key to match its label, the user must choose, install or create the correct keyboard layout in software.
Physically move keys, or assign pre-established scan codes to different physical positions. The OS doesn't know or care where any key is physically; it just maps scan codes to virtual keycodes based on the current keyboard layout.
Both Enter and Numpad Enter are mapped to VK_RETURN; there is no virtual key code reserved for Numpad Enter, so no way for it to have different scan codes on different keyboard layouts. With strategy #1, any key can be turned into Enter, but not specifically Numpad Enter. With strategy #2, Numpad Enter still has the same scan code as usual.
At the hardware level, Enter sends 0x1C while Numpad Enter sends 0xE0 0x1C (source: my own observations and a document by Andries Brouwer). Windows has different ways of reporting this: with bit 24 of WM_KEYDOWN's lParam, the LLKHF_EXTENDED flag for low level keyboard hooks, the RI_KEY_E0 flag for Raw Input, and possibly more.
In short, it is safe to assume that Numpad Enter is 0x1C plus the extended-key flag, since in any other case, it is impossible to identify.
I know that on my keyboard it is 0x9C (156)
I assume that you received this value from DirectInput, which defines an enum constant DIK_NUMPADENTER with value 0x9C. This value is not a scan code.
Anders makes a good point - I don't know of a way to tell if that key is present on (one of the) keyboard (s) present on any particular system. Also, don't forget about the Onscreen Keyboard and touch devices in general.
Why not simply bind your function to both keys regardless? Do you have a good reason not to do this?
As an addition to #Lexikos great answer:
The scan code is the value that the keyboard hardware generates when
the user presses a key. It is a device-dependent value that identifies
the key pressed, as opposed to the character represented by the key.
This was true in encient days. At least since Windows NT system uses PS/2 Scan Code Set 1 for all keyboard APIs. With some bugs that are specifically supported for backwards compatibility (for example NumLock and Pause scan codes are swapped. They are special.).
Under all Microsoft operating systems, all keyboards actually transmit
Scan Code Set 2 values down the wire from the keyboard to the keyboard
port. These values are translated to Scan Code Set 1 by the i8042 port
chip. The rest of the operating system, and all applications that
handle scan codes expect the values to be from Scan Code Set 1. Scan
Code Set 3 is not used or required for operation of Microsoft
operating systems. (Keyboard Scan Code Specification Revision 1.3a — March 16, 2000)
Because of this some API docs are reffering to scan codes as to virtual scan codes.
Modern USB or Bluetooth keyboard are using HID protocol with its HID Usage IDs to report key presses (see 10 Keyboard/Keypad Page (0x07) in HID Usage Tables spec for a list of possible keyboard key Usage IDs).
These HID Usages get converted to PS/2 Scan Code Set 1 by kbdclass driver (HID client mapper driver for keyboards) via call to HidP_TranslateUsagesToI8042ScanCodes API. It works according to published spec. So we actually have a published scan code list that is used in Windows. If you're interested in history behind this scan code mess - there is a good page.
There is no way to detect if keypad Enter button is present on particular keyboard hardware.
I have an old windows application with it's Ocxs. I want to localize it's OCX to arabic. no problem on changing labels and strings.
but I can't change layout to Right to left.
I find some resources about using Mirroring in windows. but the provided samples don't help me. Link1 & Link2
I'm not a VB fan and don't have enough experience.
Is there any clear and tested approach for VB to mirroring UI?
From Platform SDK 2001
Complex Scripts in Edit Controls
A complex script is a language whose printed form is not laid out in a simple way. For example, a complex script may allow bi-directional rendering, contextual shaping of glyphs, or combining characters. The standard edit controls have been extended to support multilingual text and complex scripts. This includes not only input and display, but also correct cursor movement over character clusters (in Thai and Devanagari script, for example).
A well-written application will receive this support automatically, without modification. Again, you should consider adding support for right-to-left reading order and right alignment. In this case, toggle the extended style flags of the edit control window to control these attributes, as shown in the following example:
// ID_EDITCONTROL is the control ID in the resource file.
HANDLE hWndEdit = GetDlgItem(hDlg, ID_EDITCONTROL);
LONG lAlign = GetWindowLong(hWndEdit, GWL_EXSTYLE) ;
// To toggle alignment
lAlign ^= WS_EX_RIGHT ;
// To toggle reading order
lAlign ^= WS_EX_RTLREADING ;
After setting the lAlign value, enable the new display by setting the extended style of the edit control window as follows:
// This assumes your edit control is in a dialog box. If not,
// get the edit control handle from another source.
SetWindowLong(hWndEdit, GWL_EXSTYLE, lAlign);
InvalidateRect(hWndEdit, NULL, FALSE);
Windows 2000/XP: The standard edit control supports a context menu that allows the user to toggle the reading order and insert/display Unicode bi-directional control characters.
I am calling querying the extended window styles of a window using the GetWindowLog property and it is returning values in many cases that are not documented in msdn.
Particularly 0x00000800L and 0x00000100L or a combination of the two. Does anyone have information about these values, or a more complete list than what is documented on the msdn site?
I ran across this thread while looking for an answer to why this value changes when Microsoft Word "disappears" a window. I maintain an app that tracks the HWND values in order to do application sharing. This works well, but Microsoft Office applications often handle these in unusual ways. In this particular case, I found that if you do the following in Microsoft Word 2013:
Open two new documents in separate windows.
Save the HWND values for both windows.
Close one of the two windows.
Both HWND values will, when interrogated with the IsWindow, IsVisible, etc Windows functions, appear to be normal, still visible, etc. There's no way I can find to tell that one of the windows has been closed -- except this undocumented dwExStyle value. 0x800 will be 'on' in the window that's still visible, and 'off' in the window that isn't visible any more.
(BTW, I know you're not "supposed" to save HWND values this way -- but try tracking windows for sharing without saving this value -- not so easy!)
Since 0x00000100L is listed right on the Extended Window Styles page it is a little unclear to me if you mean the normal or extended style so I'll describe both.
Style:
Dialog & old (user32) controls
0xFFFF for control/dialog specific styles
Common control:
0x00FF is generally used by the shared common control styles (CCS_NORESIZE, CCS_TOP etc)
0xFF00 for control specific styles, for a toolbar you would have TBSTYLE_LIST, TBSTYLE_TRANSPARENT etc
ExStyle:
0x00000100L=WS_EX_WINDOWEDGE
0x00000800L=Don't know, undocumented flag maybe (Edit: ReactOS has/had 0x00000800 as WS_EX_MAKEVISIBLEWHENUNGHOSTED, that does not mean that it has the same meaning on windows since ReactOS is not 100% compatible with windows)
Jeremy, this is just a bug of GetWindowInfo (for any OS after Win98: 2k, XP, Vista, Win7).
see http://rsdn.ru/forum/winapi/3362548.all.aspx ("WINDOWINFO.dwExStyle error")
try small tester therefrom: http://files.rsdn.ru/42164/wi_exstyle.zip
kero
I love stretching my terminal on unix. What is the history or reason behind windows lame command line?
It isn't. You can right click the title bar, select properties, and in the "Layout" tab alter the screen buffer size (line width and scrollback) and the window size (viewport size). If you started cmd from a shortcut, you can save these settings for future sessions.
If you are mouse-phobic you can also just type this inside the cmd window:
mode <cols>,<lines>
mode 80,25
mode 120,50
etc.
It's not limited.
Run cmd.exe
Click on the icon in the upper left hand of the screen.
Select Properties
Select the Layout tab.
Set the buffer and window widths to whatever you like.
Click OK
Select Save Properties for future...
Click OK.
You might want to check out Console. It's an open source app that lets you run multiple shells in a tabbed environment. You can also set the alpha-transparency of the shells.
RE: Because MS value "backwards compatibility" over a lot of things and in this case I suspect it's a misplaced belief that it will somehow unnerve people if they don't have their standard 80 wide window.
The backwards compatibility works pretty terribly, though. I don't imagine Microsoft was pretty thorough about their implementation of it, and I do believe Microsoft is the poster boy for making sure newer versions won't work on older versions. A lot doesn't work properly under COMMAND.COM, which considerably sabotages the usefulness it possesses, not to mention that you have to enter DOSONLY to make some programs run properly, plus Microsoft has been removing useful commands. Honestly, I can't imagine Microsoft holds "backwards compatibility" in much of a high regard.
Furthermore, I think the real reason why the line length is at a standard of 80 columns is because most command-line programs, etc. operate under the assumption that the user is capped at an 80 column prompt, meaning that increasing the width can cause formatting errors or worse possibly break programs altogether.
As jmucchiello mentioned, MODE will work fine for resizing the window if you feel like it.
Configures system devices.
Serial port: MODE COMm[:] [BAUD=b] [PARITY=p] [DATA=d] [STOP=s]
[to=on|off] [xon=on|off] [odsr=on|off]
[octs=on|off] [dtr=on|off|hs]
[rts=on|off|hs|tg] [idsr=on|off]
Device Status: MODE [device] [/STATUS]
Redirect printing: MODE LPTn[:]=COMm[:]
Select code page: MODE CON[:] CP SELECT=yyy
Code page status: MODE CON[:] CP [/STATUS]
Display mode: MODE CON[:] [COLS=c] [LINES=n]
Typematic rate: MODE CON[:] [RATE=r DELAY=d]
If you have DOSONLY enabled on your CONFIG.NT, however, when you open COMMAND.COM, it will inherit a proper DOS-style line resolution from cmd.exe, but you cannot invoke MODE from inside COMMAND.COM. If you wish to resize inside COMMAND.COM, you will have to use 16-bit assembly instructions, like so:
80x50 Line Resolution (No framebuffer, no SVGA, virtually universally supported.)
DEBUG
A100
MOV AX,1112
INT 10
INT 20
G
Q
132x60 Line Resolution (No framebuffer, requires SVGA. Won't work on ATI gfx cards, usually works on nVidia gfx cards, afaict always works on Intel integrated gfx cards.)
DEBUG
A100
MOV AX,4F02
MOV BX,010C
INT 10
INT 20
G
Q
If you enter this on your COMMAND.COM, it will give you the specified resolution. (Warning: If your monitor is ancient enough not to support the mode, you might wind up destroying it. Side-note: If you can run Windows, your monitor should be fine. Disclaimer: Emphasis on should, and you've been warned, so it's not my problem if your monitor fries. ;-) However, if you use this without DOSONLY enabled, COMMAND.COM will resize back to its previous size as soon as the application (in this case, unless you wrote it to a file and executed that, DEBUG) exits.
Alternatively, you could use FreeDOS's MODE.COM, which will run properly under COMMAND.COM set to DOSONLY. You can either pull it from the disk image at the official website (freedos.org) or get it at http://www.ibiblio.org/pub/micro/pc-stuff/freedos/files/dos/mode/2005/.
New FreeDOS MODE by Eric Auer 2003-2005. License: GPL. (version 12may2005)
MODE [device] [/STA[TUS]] (show status of one or all devices)
MODE LPTn[:] cols[,[lines][,retry]] (cols or cpi, 6/8 lpi, retry p or n)
MODE LPTn[:] [COLS=...] [LINES=...] [RETRY=...] (retry: p infinite / n none)
MODE LPTn[:]=[COMn[:]|NUL] (redirect printer data to serial port or NUL)
MODE COMn[:] baud,parity,data,stop,retry (empty values allowed)
MODE COMn[:] [BAUD[HARD]=...] [PARITY=...] [DATA=...] [STOP=...] [RETRY=...]
Baud can be abbreviated to unique prefix, parity can be o/e/n/s/m, the
latter 2 mean space/mark, data can be 5..8, stop 1..2. Retry is IGNORED!
PLANNED: Retry b/e/r -> busy/error/ready if busy, p/n infinite/no retry.
MODE CON[:] [CP|CODEPAGE] [/STA[TUS]] (FreeDOS DISPLAY must be loaded)
MODE CON[:] [CP|CODEPAGE] REF[RESH] (needs DISPLAY)
MODE CON[:] [CP|CODEPAGE] SEL[ECT]=number (needs DISPLAY)
MODE CON[:] [CP|CODEPAGE] PREP[ARE]=((codepage) filename) (needs DISPLAY)
Use PREP=((,cp2,cp3,,cp5) ...) to prep codepages in other buffers.
MODE [40|80|BW40|BW80|CO40|CO80|MONO][,rows] (rows can be 25, 28, 43 or 50)
Use 8, 14 or 16 as 'rows' value if you only want to change the font.
MODE [CO40|CO80|...],[R|L][,T] (shift CGA left/right, T is interactive mode)
MODE CON[:] [NUMLOCK|CAPSLOCK|SCROLLLOCK|SWITCHAR]=value
Value can be: + or - for the locks or a character for switchar.
MODE CON[:] [COLS=...] [LINES=...] (possible values depend on your hardware)
MODE CON[:] [RATE=...] [DELAY=...] (default rate 20, default delay 1)
Rate can be 1..32 for 2..30 char/sec, delay can be 1..4 for 1/4..4/4 sec.
For the same reasons as with the ASM code I provided, unless you execute it in COMMAND.COM with DOSONLY added to your CONFIG.NT file, the window will immediately rebound to its previous size once MODE.COM exits.
Lastly, as others have stated, it is also possible to modify these settings simply by right clicking on the command prompt's title bar, and modifying Properties -> Layout. Similarly, you can set the resolution for any shortcuts to CMD.EXE and batch files (Right click the shortcut -> Properties -> Layout). This only works for CMD.EXE, however, not COMMAND.COM.
A simple command to fix the window size that I use all the time:
wmic
It will open the Windows Management Instrumentation Command-line and remove the size limits.
Then just close it with Ctrl+C.
I don't know the history behind it, but this wishlist item from the author of PuTTy is an interesting post that explains the technical hurdles involved with any type of cmd.exe replacement that isn't lame:
http://www.chiark.greenend.org.uk/~sgtatham/putty/wishlist/win-command-prompt.html
You don't mention that you're looking for a replacement, but if so you might also check out some of the cmd.exe replacements like Console 2 or JP Software's Take Command etc. I've also had some good experiences with PuTTy-Cyg which lets you use PuTTy as a cygwin shell.
While the width is not limited as other answers show, I've always found it strange that one can drag and resize the height with the mouse, but not the width.
I think the default 80 character width is related to compatibility with old programs that assume the terminal won't be more than 80 characters wide. I don't think this has been a realistic reason for a decade or so, though.
As others have pointed out, it's not limited to 80 characters wide, but my guess as to why it defaults to 80 characters would be that it's left over from the DOS days where CRT displays were 80 characters wide.
See also
You could also use a different terminal application, such as Console2, which allows you to resize the window all you want (among other things, such as transparency, and the ability to use any font you'd like). It's a great application, I've switched to it and now I only use cmd.exe when I absolutely have to.
Since it will scroll left to right as well as up and down, the very first thing I do on a system is define my width as 180 and save it. That's generally enough so that stack traces don't have to wrap for the most part, but not so much that you are waisting a ton of space.
While you're at it, set the vertical size (scrollback buffer) to all 9's. You'll be glad you did some day.
Because MS value "backwards compatibility" over a lot of things and in this case I suspect it's a misplaced belief that it will somehow unnerve people if they don't have their standard 80 wide window.
Of course it could be that it was programmed for a fixed 80 chars width when that was pretty much universal, and the additional property settings were a bit of a hack.
It IS limited. Check it out. (I mean window size NOT buffer)
You will find that the maximum width you can set is limited but varies according to your screen resolution. If your resolution is set to 1024 x 768 you will find that you can only get to 128 on the command prompt width. 128/1024=.125
you will find that ratio to be consistent across the board. I have an RDP session running at 2000x768 (across two of my three monitors) and get a max width of 250.
Now, that actaully turns out to be a little bigger than your actaul monitor size but I have three monitors all running individual desktops. (so in essence, 3 1024x768 resolutions) and if I want to do something SO SIMPLE as stretch a command prompt across 2 or more monitors, I CAN'T. (I want to when doing things with very long paths (diruse.exe/etc.)...
-c
This isn't closed. So it should be noted that Windows Terminal is now is changing all of this:
https://github.com/microsoft/terminal
https://www.theverge.com/2020/1/9/21059316/microsoft-windows-terminal-crt-effects-retro-search-tabs-features
https://devblogs.microsoft.com/commandline/windows-command-line-backgrounder/
https://github.com/microsoft/terminal/blob/master/doc/terminal-v1-roadmap.md
https://www.microsoft.com/en-us/p/windows-terminal-preview/9n0dx20hk701?activetab=pivot:overviewtab
Because improving the usability and functionality of anything that Unix/GNU-like development requires will undermine Windows as a commercial platform for Microsoft's partners. Preventing this means other large companies' products for developers, such as improved terminals, and other general third party products, like word processors, video players etc. aren't competing with existing Unix/GNU software. Without this, Windows wouldn't be a profitable platform, and Microsoft would lose its desktop monopoly.
This is why the terminal sucks, there's no POSIX API, no C99 support in MSVC and the list goes on. To clarify, common Unix/GNU technologies and development are intentionally unsupported so that large commercial software houses don't have to compete with them.