我整天都在努力解决这个问题,但我仍然没有取得任何进展。
我正在尝试在连接到物理键盘的LED上重现虚拟钢琴键盘(由MIDI文件驱动),以便我的妻子可以学习如何更快地弹钢琴(圣诞节礼物)。这是程序的图片:
(或者应该这样做)我在全屏截图后输入了Paint.NET中测量的键盘坐标。要求用户将软件全屏显示。然后,我计算所有按键中间的坐标,并在未激活时获取按键的颜色。最后,我检查所有白色键是否具有相同的颜色,以及黑色键是否具有相同的颜色(以确保正确显示键盘)。 以后,我将永远循环,获取每个键的颜色,如果该键的颜色已从“静止”状态更改,则点亮物理键盘上的相应LED。
我知道我在正确的位置选择了颜色,因为SetPixel()在所有键的中间显示红色像素点(如代码所示)。但是,GetPixel仍然经常多次返回错误的值(白键的时间是时间的1/4,黑键的时间总是)。发生什么事了?
A在项目中添加了清单文件,该文件成功将桌面的大小修改为1920x1080的正确值-但是,即使RGB值有所变化,它们仍处于关闭状态 -我添加了captureAndSave()函数,以防计算机在执行屏幕捕获(获取所有输入坐标)时,或者我在SetPixel()中看到“不同于”我的东西时,因为这样做有效-但图像是确实一样,所以我不知道发生了什么。 -许多调试运行...
(跳到VirtualKeyboard :: init())
#include <iostream>
#include <windows.h>
using namespace std;
const unsigned int N_WHITE_KEYS = 49;
const unsigned int N_PIANO_KEYS = N_WHITE_KEYS+35;
const unsigned int N_ABSENT_BLK_KEYS = N_WHITE_KEYS*2-N_PIANO_KEYS-1;
const unsigned int ABSENT_BLK_KEYS[N_ABSENT_BLK_KEYS] = {3,7,10,14,17,21,24,28,31,35,38,42,45}; //TODO: find a formula rather than this list
const unsigned int VKxLeft = 19,
VKyTop = 150,
VKxRight = 1731,
VKyBtm = 324;
//TEMP
#include <stdio.h>
bool captureAndSave(const HWND& hWnd, int nBitCount, const char* szFilePath)
{
if(!szFilePath || !strlen(szFilePath))
{
cout << "bad function arguments\n";
return false;
}
//calculate the number of color indexes in the color table
int nColorTableEntries = -1;
switch(nBitCount)
{
case 1:
nColorTableEntries = 2;
break;
case 4:
nColorTableEntries = 16;
break;
case 8:
nColorTableEntries = 256;
break;
case 16:
case 24:
case 32:
nColorTableEntries = 0;
break;
default:
nColorTableEntries = -1;
break;
}
if(nColorTableEntries == -1)
{
cout << "bad bits-per-pixel argument\n";
return false;
}
HDC hDC = GetDC(hWnd);
HDC hMemDC = CreateCompatibleDC(hDC);
int nWidth = 0;
int nHeight = 0;
if(hWnd != HWND_DESKTOP)
{
RECT rect;
GetClientRect(hWnd, &rect);
nWidth = rect.right - rect.left;
nHeight = rect.bottom - rect.top;
}
else
{
nWidth = ::GetSystemMetrics(SM_CXSCREEN);
nHeight = ::GetSystemMetrics(SM_CYSCREEN);
}
HBITMAP hBMP = CreateCompatibleBitmap(hDC, nWidth, nHeight);
SelectObject(hMemDC, hBMP);
BitBlt(hMemDC, 0, 0, nWidth, nHeight, hDC, 0, 0, SRCCOPY);
int nStructLength = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorTableEntries;
LPBITMAPINFOHEADER lpBitmapInfoHeader = (LPBITMAPINFOHEADER)new char[nStructLength];
::ZeroMemory(lpBitmapInfoHeader, nStructLength);
lpBitmapInfoHeader->biSize = sizeof(BITMAPINFOHEADER);
lpBitmapInfoHeader->biWidth = nWidth;
lpBitmapInfoHeader->biHeight = nHeight;
lpBitmapInfoHeader->biPlanes = 1;
lpBitmapInfoHeader->biBitCount = nBitCount;
lpBitmapInfoHeader->biCompression = BI_RGB;
lpBitmapInfoHeader->biXPelsPerMeter = 0;
lpBitmapInfoHeader->biYPelsPerMeter = 0;
lpBitmapInfoHeader->biClrUsed = nColorTableEntries;
lpBitmapInfoHeader->biClrImportant = nColorTableEntries;
DWORD dwBytes = ((DWORD) nWidth * nBitCount) / 32;
if(((DWORD) nWidth * nBitCount) % 32) {
dwBytes++;
}
dwBytes *= 4;
DWORD dwSizeImage = dwBytes * nHeight;
lpBitmapInfoHeader->biSizeImage = dwSizeImage;
LPBYTE lpDibBits = 0;
HBITMAP hBitmap = ::CreateDIBSection(hMemDC, (LPBITMAPINFO)lpBitmapInfoHeader, DIB_RGB_COLORS, (void**)&lpDibBits, NULL, 0);
SelectObject(hMemDC, hBitmap);
BitBlt(hMemDC, 0, 0, nWidth, nHeight, hDC, 0, 0, SRCCOPY);
ReleaseDC(hWnd, hDC);
BITMAPFILEHEADER bmfh;
bmfh.bfType = 0x4d42; // 'BM'
int nHeaderSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorTableEntries;
bmfh.bfSize = 0;
bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorTableEntries;
FILE *pFile = 0;
pFile = fopen(szFilePath, "wb");
if(!pFile)
{
::DeleteObject(hBMP);
::DeleteObject(hBitmap);
delete[]lpBitmapInfoHeader;
cout << "can not open file\n";
return false;
}
DWORD nColorTableSize = 0;
if (nBitCount != 24)
nColorTableSize = (1 << nBitCount) * sizeof(RGBQUAD);
else
nColorTableSize = 0;
fwrite(&bmfh, sizeof(BITMAPFILEHEADER), 1, pFile);
fwrite(lpBitmapInfoHeader, nHeaderSize,1,pFile);
if(nBitCount < 16)
{
int nBytesWritten = 0;
RGBQUAD *rgbTable = new RGBQUAD[nColorTableEntries * sizeof(RGBQUAD)];
//fill RGBQUAD table and write it in file
for(int i = 0; i < nColorTableEntries; ++i)
{
rgbTable[i].rgbRed = rgbTable[i].rgbGreen = rgbTable[i].rgbBlue = i;
rgbTable[i].rgbReserved = 0;
fwrite(&rgbTable[i], sizeof(RGBQUAD), 1, pFile);
}
delete[]rgbTable;
/*
RGBQUAD rgb;
for (DWORD i = 0; i < nColorTableEntries ; i++)
{
rgb.rgbBlue = rgb.rgbGreen = rgb.rgbRed = (BYTE)(i*(255/(nColorTableEntries-1)));
nBytesWritten = fwrite(&rgb, 1, sizeof(rgb), pFile);
if (nBytesWritten != sizeof(rgb))
{
printf("error while writing rgb header\n");
fclose(pFile);
::DeleteObject(hBMP);
::DeleteObject(hBitmap);
delete[]lpBitmapInfoHeader;
return false;
}
}
*/
}
fwrite(lpDibBits, dwSizeImage, 1, pFile);
fclose(pFile);
::DeleteObject(hBMP);
::DeleteObject(hBitmap);
delete[]lpBitmapInfoHeader;
}
//End TEMP
inline bool SameColours(COLORREF const &a, COLORREF const &b) {
bool ret = true;
ret &= GetRValue(a) == GetRValue(b);
ret &= GetGValue(a) == GetGValue(b);
ret &= GetBValue(a) == GetBValue(b);
return ret;
}
class VirtualKeyboard
{
COLORREF keyColUnpressed[N_PIANO_KEYS];
unsigned int keyX[N_PIANO_KEYS]; //White then black, from left to right
unsigned int keyY[N_PIANO_KEYS]; //White then black, from left to right
public:
bool init(unsigned int xLeft, unsigned int yTop, unsigned int xRight, unsigned yBtm) {
bool ret = true;
//Calculate parameters of the virtual keyboard
const float whtKeyHeight = (yBtm-yTop);
const float whtKeyWidth = float(xRight-xLeft)/(N_WHITE_KEYS);
//Calculate coordinates of the white keys
for(unsigned int i = 0; i < N_WHITE_KEYS ; ++i) {
keyX[i]=xLeft+(i+1.f/2)*float(whtKeyWidth);
keyY[i]=yTop+3.f/4*float(whtKeyHeight);
}
//Calculate coordinates of the black keys
unsigned int iBlkKey = 0;
for(unsigned int i = 0 ; i < N_WHITE_KEYS-1 ; ++i) {
//Determine if there is a black key
bool skip = false;
//Some black keys are absent from the offset white keys pattern - skip if applicable
for(unsigned int j = 0 ; j < N_ABSENT_BLK_KEYS ; ++j) {
if(i+1 == ABSENT_BLK_KEYS[j]) {
skip = true;
break;
}
}
//If that key exists, add it to the list
if(!skip) {
keyX[iBlkKey+N_WHITE_KEYS]=xLeft+whtKeyWidth*(i+1);
keyY[iBlkKey+N_WHITE_KEYS]=yTop+1.f/4*float(whtKeyHeight);
iBlkKey++;
}
}
//Capture the screen
HDC hdcScreen = ::GetDC(GetDesktopWindow());
captureAndSave(GetDesktopWindow(),32,"./capture.bmp");
//And fill in the colors "at rest" for all the keys
for(unsigned int i = 0 ; i < N_PIANO_KEYS ; ++i) {
keyColUnpressed[i] = ::GetPixel(hdcScreen, keyX[i], keyY[i]);
unsigned int r = GetRValue(keyColUnpressed[i]);
unsigned int g = GetGValue(keyColUnpressed[i]);
unsigned int b = GetBValue(keyColUnpressed[i]);
::SetPixel(hdcScreen, keyX[i], keyY[i], RGB(255,0,0)); //DEBUG: Breakpoint on this line, the RGB values are wrong for some keys (e.g. i=8 and all blacks)
Sleep(100);
}
ReleaseDC(GetDesktopWindow(),hdcScreen);
//Sanity check : all white keys should have the same colour, and all black keys their own colour as well
for(unsigned int i = 1 ; i < N_PIANO_KEYS ; ++i) {
if(i != 1 && i != N_WHITE_KEYS) {
if(
!SameColours(
keyColUnpressed[i],(i < N_WHITE_KEYS ? keyColUnpressed[0]
: keyColUnpressed[N_WHITE_KEYS])
)
)
{
ret = false;
break;
}
}
}
return 0;
}
};
int main()
{
VirtualKeyboard vk;
cout << "You have 3 seconds to minimize this window and maximise MidiSheetMusic" << endl;
Sleep(3000);
cout << "Result of init() : " << vk.init(VKxLeft, VKyTop, VKxRight, VKyBtm) << endl;
while(1)
{
//Get all keys pixels and reproduce on the LEDs on the physical keyboard
Sleep(10); //Runs while not Ctrl+c
}
return 0;
}
非常感谢您。