void gwinResize(GHandle gh, coord_t width, coord_t height) { gh->width = width; gh->height = height; if (gh->width < MIN_WIN_WIDTH) { gh->width = MIN_WIN_WIDTH; } if (gh->height < MIN_WIN_HEIGHT) { gh->height = MIN_WIN_HEIGHT; } if (gh->x+gh->width > gdispGGetWidth(gh->display)) gh->width = gdispGGetWidth(gh->display) - gh->x; if (gh->y+gh->height > gdispGGetHeight(gh->display)) gh->height = gdispGGetHeight(gh->display) - gh->y; _gwinUpdate(gh); }
void gwinMove(GHandle gh, coord_t x, coord_t y) { gh->x = x; gh->y = y; if (gh->x < 0) gh->x = 0; if (gh->y < 0) gh->y = 0; if (gh->x > gdispGGetWidth(gh->display)-MIN_WIN_WIDTH) gh->x = gdispGGetWidth(gh->display)-MIN_WIN_WIDTH; if (gh->y > gdispGGetHeight(gh->display)-MIN_WIN_HEIGHT) gh->y = gdispGGetHeight(gh->display)-MIN_WIN_HEIGHT; if (gh->x+gh->width > gdispGGetWidth(gh->display)) gh->width = gdispGGetWidth(gh->display) - gh->x; if (gh->y+gh->height > gdispGGetHeight(gh->display)) gh->height = gdispGGetHeight(gh->display) - gh->y; _gwinUpdate(gh); }
void _tsOrientClip(MouseReading *pt, GDisplay *g, bool_t doClip) { coord_t w, h; w = gdispGGetWidth(g); h = gdispGGetHeight(g); #if GDISP_NEED_CONTROL && !GINPUT_MOUSE_NO_ROTATION switch(gdispGGetOrientation(g)) { case GDISP_ROTATE_0: break; case GDISP_ROTATE_90: { coord_t t = pt->x; pt->x = w - 1 - pt->y; pt->y = t; } break; case GDISP_ROTATE_180: pt->x = w - 1 - pt->x; pt->y = h - 1 - pt->y; break; case GDISP_ROTATE_270: { coord_t t = pt->y; pt->y = h - 1 - pt->x; pt->x = t; } break; default: break; } #endif if (doClip) { if (pt->x < 0) pt->x = 0; else if (pt->x >= w) pt->x = w-1; if (pt->y < 0) pt->y = 0; else if (pt->y >= h) pt->y = h-1; } }
static void GetMouseReading(GMouse *m) { GMouseReading r; // Step 1 - Get the Raw Reading { m->flags &= ~GMOUSE_FLG_NEEDREAD; if (!gmvmt(m)->get(m, &r)) return; } // Step 2 - Handle touch and button 0 debouncing { // Clean off button garbage r.buttons &= GINPUT_MOUSE_BTN_MASK; #if !GINPUT_TOUCH_NOTOUCH // If touch then calculate button 0 from z if ((gmvmt(m)->d.flags & GMOUSE_VFLG_TOUCH)) { if (gmvmt(m)->z_min <= gmvmt(m)->z_max) { if (r.z >= gmvmt(m)->z_touchon) r.buttons |= GINPUT_MOUSE_BTN_LEFT; else if (r.z <= gmvmt(m)->z_touchoff) r.buttons &= ~GINPUT_MOUSE_BTN_LEFT; else return; // bad transitional reading } else { if (r.z <= gmvmt(m)->z_touchon) r.buttons |= GINPUT_MOUSE_BTN_LEFT; else if (r.z >= gmvmt(m)->z_touchoff) r.buttons &= ~GINPUT_MOUSE_BTN_LEFT; else return; // bad transitional reading } } // Devices with poor button 0 transitioning need debouncing if ((gmvmt(m)->d.flags & GMOUSE_VFLG_POORUPDOWN)) { // Are we in a transition test if ((m->flags & GMOUSE_FLG_INDELTA)) { if (!((r.buttons ^ m->r.buttons) & GINPUT_MOUSE_BTN_LEFT)) { // Transition failed m->flags &= ~GMOUSE_FLG_INDELTA; return; } // Transition succeeded m->flags &= ~GMOUSE_FLG_INDELTA; // Should we start a transition test } else if (((r.buttons ^ m->r.buttons) & GINPUT_MOUSE_BTN_LEFT)) { m->flags |= GMOUSE_FLG_INDELTA; return; } } #endif #if !GINPUT_TOUCH_NOCALIBRATE_GUI // Stop here with just the raw x,y reading during calibration if ((m->flags & GMOUSE_FLG_IN_CAL)) { if ((r.buttons & GINPUT_MOUSE_BTN_LEFT)) { m->r.x = r.x; m->r.y = r.y; } m->r.buttons = r.buttons; return; } #endif } // Step 3 - Apply calibration, rotation and display clipping { // If the mouse is up we may need to keep our previous position if ((gmvmt(m)->d.flags & GMOUSE_VFLG_ONLY_DOWN) && !(r.buttons & GINPUT_MOUSE_BTN_LEFT)) { r.x = m->r.x; r.y = m->r.y; } else { #if !GINPUT_TOUCH_NOCALIBRATE // Do we need to calibrate the reading? if ((m->flags & GMOUSE_FLG_CALIBRATE)) CalibrationTransform(&r, &m->caldata); #endif // We can't clip or rotate if we don't have a display if (m->display) { coord_t w, h; // We now need display information w = gdispGGetWidth(m->display); h = gdispGGetHeight(m->display); #if GDISP_NEED_CONTROL // Do we need to rotate the reading to match the display if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_SELFROTATION)) { coord_t t; switch(gdispGGetOrientation(m->display)) { case GDISP_ROTATE_0: break; case GDISP_ROTATE_90: t = r.x; r.x = w - 1 - r.y; r.y = t; break; case GDISP_ROTATE_180: r.x = w - 1 - r.x; r.y = h - 1 - r.y; break; case GDISP_ROTATE_270: t = r.y; r.y = h - 1 - r.x; r.x = t; break; default: break; } } #endif // Do we need to clip the reading to the display if ((m->flags & GMOUSE_FLG_CLIP)) { if (r.x < 0) r.x = 0; else if (r.x >= w) r.x = w-1; if (r.y < 0) r.y = 0; else if (r.y >= h) r.y = h-1; } } } } // Step 4 - Apply jitter detection #if !GINPUT_TOUCH_NOTOUCH { const GMouseJitter *pj; uint32_t diff; // Are we in pen or finger mode pj = (m->flags & GMOUSE_FLG_FINGERMODE) ? &gmvmt(m)->finger_jitter : &gmvmt(m)->pen_jitter; // Is this just movement jitter if (pj->move > 0) { diff = (uint32_t)(r.x - m->r.x) * (uint32_t)(r.x - m->r.x) + (uint32_t)(r.y - m->r.y) * (uint32_t)(r.y - m->r.y); if (diff < (uint32_t)pj->move * (uint32_t)pj->move) { r.x = m->r.x; r.y = m->r.y; } } // Check if the click has moved outside the click area and if so cancel the click if (pj->click > 0 && (m->flags & GMOUSE_FLG_CLICK_TIMER)) { diff = (uint32_t)(r.x - m->clickpos.x) * (uint32_t)(r.x - m->clickpos.x) + (uint32_t)(r.y - m->clickpos.y) * (uint32_t)(r.y - m->clickpos.y); if (diff > (uint32_t)pj->click * (uint32_t)pj->click) m->flags &= ~GMOUSE_FLG_CLICK_TIMER; } } #endif // Step 5 - Click, context-click and other meta event detection { uint16_t upbtns, dnbtns; // Calculate button transitions dnbtns = r.buttons & ~m->r.buttons; upbtns = ~r.buttons & m->r.buttons; // Left mouse down generates the Mouse-down meta event if ((dnbtns & GINPUT_MOUSE_BTN_LEFT)) r.buttons |= GMETA_MOUSE_DOWN; // Left mouse up generates the Mouse-up meta event if ((upbtns & GINPUT_MOUSE_BTN_LEFT)) r.buttons |= GMETA_MOUSE_UP; // Left/Right mouse down starts the click timer if ((dnbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT))) { m->clickpos.x = r.x; m->clickpos.y = r.y; m->clicktime = gfxSystemTicks(); m->flags |= GMOUSE_FLG_CLICK_TIMER; } // Left/Right mouse up with the click timer still running may generate a click or context click if ((upbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT)) && (m->flags & GMOUSE_FLG_CLICK_TIMER)) { m->flags &= ~GMOUSE_FLG_CLICK_TIMER; m->clicktime = gfxSystemTicks() - m->clicktime; // Was this a short click? if (m->clicktime <= gfxMillisecondsToTicks(GINPUT_MOUSE_CLICK_TIME)) { if ((upbtns & GINPUT_MOUSE_BTN_RIGHT)) r.buttons |= GMETA_MOUSE_CXTCLICK; if ((upbtns & GINPUT_MOUSE_BTN_LEFT)) r.buttons |= GMETA_MOUSE_CLICK; } #if !GINPUT_TOUCH_NOTOUCH // Was this a long click on a touch device? if ((gmvmt(m)->d.flags & GMOUSE_VFLG_TOUCH) && m->clicktime >= gfxMillisecondsToTicks(GINPUT_TOUCH_CXTCLICK_TIME)) r.buttons |= GMETA_MOUSE_CXTCLICK; #endif } } // Step 6 - Send the event to the listeners that are interested. { GSourceListener *psl; // Send to the "All Mice" source listeners psl = 0; while ((psl = geventGetSourceListener((GSourceHandle)&MouseTimer, psl))) SendMouseEvent(psl, m, &r); // Send to the mouse specific source listeners psl = 0; while ((psl = geventGetSourceListener((GSourceHandle)m, psl))) SendMouseEvent(psl, m, &r); } // Step 7 - Finally save the results m->r.x = r.x; m->r.y = r.y; m->r.z = r.z; m->r.buttons = r.buttons; }
static uint32_t CalibrateMouse(GMouse *m) { coord_t w, h; point cross[4]; // The locations of the test points on the display point points[4]; // The x, y readings obtained from the mouse for each test point uint32_t err; #if GDISP_NEED_TEXT font_t font1, font2; #endif #if GDISP_NEED_TEXT font1 = gdispOpenFont(CALIBRATION_FONT); if (!font1) font1 = gdispOpenFont("*"); font2 = gdispOpenFont(CALIBRATION_FONT2); if (!font2) font2 = gdispOpenFont("*"); #endif err = 0; w = gdispGGetWidth(m->display); h = gdispGGetHeight(m->display); #if GDISP_NEED_CLIP gdispGSetClip(m->display, 0, 0, w, h); #endif // Ensure we get minimaly processed readings for the calibration m->flags |= GMOUSE_FLG_IN_CAL; // Set up our calibration locations if ((gmvmt(m)->d.flags & GMOUSE_VFLG_CAL_EXTREMES)) { cross[0].x = 0; cross[0].y = 0; cross[1].x = w-1; cross[1].y = 0; cross[2].x = w-1; cross[2].y = h-1; cross[3].x = w/2; cross[3].y = h/2; } else { cross[0].x = w/4; cross[0].y = h/4; cross[1].x = w-w/4; cross[1].y = h/4; cross[2].x = w-w/4; cross[2].y = h-h/4; cross[3].x = w/2; cross[3].y = h/2; } // Set up the calibration display gdispGClear(m->display, Blue); #if GDISP_NEED_TEXT gdispGFillStringBox(m->display, 0, CALIBRATION_TITLE_Y, w, CALIBRATION_TITLE_HEIGHT, CALIBRATION_TITLE, font1, CALIBRATION_TITLE_COLOR, CALIBRATION_TITLE_BACKGROUND, justifyCenter); #endif // Calculate the calibration { unsigned i, maxpoints; maxpoints = (gmvmt(m)->d.flags & GMOUSE_VFLG_CAL_TEST) ? 4 : 3; // Loop through the calibration points for(i = 0; i < maxpoints; i++) { int32_t px, py; unsigned j; // Draw the current calibration point CalibrationCrossDraw(m, &cross[i]); // Get a valid "point pressed" average reading do { // Wait for the mouse to be pressed while(!(m->r.buttons & GINPUT_MOUSE_BTN_LEFT)) gfxSleepMilliseconds(CALIBRATION_POLL_PERIOD); // Sum samples taken every CALIBRATION_POLL_PERIOD milliseconds while the mouse is down px = py = j = 0; while((m->r.buttons & GINPUT_MOUSE_BTN_LEFT)) { // Limit sampling period to prevent overflow if (j < CALIBRATION_MAXPRESS_PERIOD/CALIBRATION_POLL_PERIOD) { px += m->r.x; py += m->r.y; j++; } gfxSleepMilliseconds(CALIBRATION_POLL_PERIOD); } // Ignore presses less than CALIBRATION_MAXPRESS_PERIOD milliseconds } while(j < CALIBRATION_MINPRESS_PERIOD/CALIBRATION_POLL_PERIOD); points[i].x = px / j; points[i].y = py / j; // Clear the current calibration point CalibrationCrossClear(m, &cross[i]); } } // Apply 3 point calibration algorithm CalibrationCalculate(m, cross, points); /* Verification of correctness of calibration (optional) : * See if the 4th point (Middle of the screen) coincides with the calibrated * result. If point is within +/- Squareroot(ERROR) pixel margin, then successful calibration * Else return the error. */ if ((gmvmt(m)->d.flags & GMOUSE_VFLG_CAL_TEST)) { const GMouseJitter *pj; // Are we in pen or finger mode pj = (m->flags & GMOUSE_FLG_FINGERMODE) ? &gmvmt(m)->finger_jitter : &gmvmt(m)->pen_jitter; // Transform the co-ordinates CalibrationTransform((GMouseReading *)&points[3], &m->caldata); // Do we need to rotate the reading to match the display #if GDISP_NEED_CONTROL if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_SELFROTATION)) { coord_t t; switch(gdispGGetOrientation(m->display)) { case GDISP_ROTATE_0: break; case GDISP_ROTATE_90: t = points[3].x; points[3].x = w - 1 - points[3].y; points[3].y = t; break; case GDISP_ROTATE_180: points[3].x = w - 1 - points[3].x; points[3].y = h - 1 - points[3].y; break; case GDISP_ROTATE_270: t = points[3].y; points[3].y = h - 1 - points[3].x; points[3].x = t; break; default: break; } } #endif // Is this accurate enough? err = (points[3].x - cross[3].x) * (points[3].x - cross[3].x) + (points[3].y - cross[3].y) * (points[3].y - cross[3].y); if (err > (uint32_t)pj->calibrate * (uint32_t)pj->calibrate) { #if GDISP_NEED_TEXT // No - Display error and return gdispGFillStringBox(m->display, 0, CALIBRATION_ERROR_Y, w, CALIBRATION_ERROR_HEIGHT, CALIBRATION_ERROR_TEXT, font2, CALIBRATION_ERROR_COLOR, CALIBRATION_ERROR_BACKGROUND, justifyCenter); gfxSleepMilliseconds(CALIBRATION_ERROR_DELAY); #endif } else err = 0; } // We are done calibrating #if GDISP_NEED_TEXT gdispCloseFont(font1); gdispCloseFont(font2); #endif m->flags &= ~GMOUSE_FLG_IN_CAL; m->flags |= GMOUSE_FLG_CLIP; // Save the calibration data (if possible) if (!err) { m->flags |= GMOUSE_FLG_CALIBRATE; #if GINPUT_TOUCH_USER_CALIBRATION_SAVE SaveMouseCalibration(gdriverGetDriverInstanceNumber((GDriver *)m), &m->caldata, sizeof(GMouseCalibration)); #endif if (gmvmt(m)->calsave) gmvmt(m)->calsave(m, &m->caldata, sizeof(GMouseCalibration)); } // Force an initial reading m->r.buttons = 0; GetMouseReading(m); // Clear the screen using the GWIN default background color #if GFX_USE_GWIN gdispGClear(m->display, gwinGetDefaultBgColor()); #else gdispGClear(m->display, GDISP_STARTUP_COLOR); #endif return err; }
static inline void CalibrationCalculate(GMouse *m, const point *cross, const point *points) { float dx; coord_t c0, c1, c2; (void) m; // Work on x values c0 = cross[0].x; c1 = cross[1].x; c2 = cross[2].x; #if GDISP_NEED_CONTROL if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_SELFROTATION)) { /* Convert all cross points back to GDISP_ROTATE_0 convention * before calculating the calibration matrix. */ switch(gdispGGetOrientation(m->display)) { case GDISP_ROTATE_90: c0 = cross[0].y; c1 = cross[1].y; c2 = cross[2].y; break; case GDISP_ROTATE_180: c0 = c1 = c2 = gdispGGetWidth(m->display) - 1; c0 -= cross[0].x; c1 -= cross[1].x; c2 -= cross[2].x; break; case GDISP_ROTATE_270: c0 = c1 = c2 = gdispGGetHeight(m->display) - 1; c0 -= cross[0].y; c1 -= cross[1].y; c2 -= cross[2].y; break; default: break; } } #endif /* Compute all the required determinants */ dx = (float)(points[0].x - points[2].x) * (float)(points[1].y - points[2].y) - (float)(points[1].x - points[2].x) * (float)(points[0].y - points[2].y); m->caldata.ax = ((float)(c0 - c2) * (float)(points[1].y - points[2].y) - (float)(c1 - c2) * (float)(points[0].y - points[2].y)) / dx; m->caldata.bx = ((float)(c1 - c2) * (float)(points[0].x - points[2].x) - (float)(c0 - c2) * (float)(points[1].x - points[2].x)) / dx; m->caldata.cx = (c0 * ((float)points[1].x * (float)points[2].y - (float)points[2].x * (float)points[1].y) - c1 * ((float)points[0].x * (float)points[2].y - (float)points[2].x * (float)points[0].y) + c2 * ((float)points[0].x * (float)points[1].y - (float)points[1].x * (float)points[0].y)) / dx; // Work on y values c0 = cross[0].y; c1 = cross[1].y; c2 = cross[2].y; #if GDISP_NEED_CONTROL if (!(gmvmt(m)->d.flags & GMOUSE_VFLG_SELFROTATION)) { switch(gdispGGetOrientation(m->display)) { case GDISP_ROTATE_90: c0 = c1 = c2 = gdispGGetWidth(m->display) - 1; c0 -= cross[0].x; c1 -= cross[1].x; c2 -= cross[2].x; break; case GDISP_ROTATE_180: c0 = c1 = c2 = gdispGGetHeight(m->display) - 1; c0 -= cross[0].y; c1 -= cross[1].y; c2 -= cross[2].y; break; case GDISP_ROTATE_270: c0 = cross[0].x; c1 = cross[1].x; c2 = cross[2].x; break; default: break; } } #endif m->caldata.ay = ((float)(c0 - c2) * (float)(points[1].y - points[2].y) - (float)(c1 - c2) * (float)(points[0].y - points[2].y)) / dx; m->caldata.by = ((float)(c1 - c2) * (float)(points[0].x - points[2].x) - (float)(c0 - c2) * (float)(points[1].x - points[2].x)) / dx; m->caldata.cy = (c0 * ((float)points[1].x * (float)points[2].y - (float)points[2].x * (float)points[1].y) - c1 * ((float)points[0].x * (float)points[2].y - (float)points[2].x * (float)points[0].y) + c2 * ((float)points[0].x * (float)points[1].y - (float)points[1].x * (float)points[0].y)) / dx; }
static bool_t read_xyz(GMouse* m, GMouseReading* pdr) { #if GMOUSE_STMPE811_TEST_MODE static GMouseReading n; #endif uint8_t status; // Button information will be regenerated pdr->buttons = 0; #if GMOUSE_STMPE811_TEST_MODE aquire_bus(m); // Set the buttons to match various touch signals if ((read_byte(m, STMPE811_REG_TSC_CTRL) & 0x80)) pdr->buttons |= 0x02; status = read_byte(m, STMPE811_REG_FIFO_STA); if (!(status & 0x20)) pdr->buttons |= 0x04; #if GMOUSE_STMPE811_GPIO_IRQPIN if (getpin_irq(m)) pdr->buttons |= 0x08; #endif if ((status & 0x20)) { // Nothing in the fifo - just return the last position and pressure pdr->x = n.x; pdr->y = n.y; pdr->z = n.z; #if GMOUSE_STMPE811_GPIO_IRQPIN write_reg(m, STMPE811_REG_INT_STA, 0xFF); #endif release_bus(m); return TRUE; } #else // Is there a new sample or a touch transition #if GMOUSE_STMPE811_GPIO_IRQPIN if(!getpin_irq(m)) return FALSE; #endif // Is there something in the fifo status = read_byte(m, STMPE811_REG_FIFO_STA); if ((status & 0x20)) { // Nothing in the fifo. // If not touched return the pseudo result if (!(read_byte(m, STMPE811_REG_TSC_CTRL) & 0x80)) { pdr->z = gmvmt(m)->z_min; #if GMOUSE_STMPE811_GPIO_IRQPIN write_reg(m, STMPE811_REG_INT_STA, 0xFF); #endif release_bus(m); return TRUE; } // No new result #if GMOUSE_STMPE811_GPIO_IRQPIN write_reg(m, STMPE811_REG_INT_STA, 0xFF); #endif release_bus(m); return FALSE; } #endif // Time to get some readings pdr->x = (coord_t)read_word(m, STMPE811_REG_TSC_DATA_X); pdr->y = (coord_t)read_word(m, STMPE811_REG_TSC_DATA_Y); #if GMOUSE_STMPE811_READ_PRESSURE pdr->z = (coord_t)read_byte(m, STMPE811_REG_TSC_DATA_Z); #else pdr->z = gmvmt(m)->z_max; #endif #if !GMOUSE_STMPE811_SLOW_CPU if (!(status & 0xC0)) { // Is there more data to come if (!(read_byte(m, STMPE811_REG_FIFO_STA) & 0x20)) _gmouseWakeup(m); } else #endif // Clear the rest of the fifo { write_reg(m, STMPE811_REG_FIFO_STA, 0x01); // FIFO reset enable write_reg(m, STMPE811_REG_FIFO_STA, 0x00); // FIFO reset disable } // All done #if GMOUSE_STMPE811_GPIO_IRQPIN write_reg(m, STMPE811_REG_INT_STA, 0xFF); #endif release_bus(m); #if GMOUSE_STMPE811_TEST_MODE // Save the result for later n.x = pdr->x; n.y = pdr->y; n.z = pdr->z; #endif // Rescale X,Y if we are using self-calibration #if GMOUSE_STMPE811_SELF_CALIBRATE #if GDISP_NEED_CONTROL switch(gdispGGetOrientation(m->display)) { default: case GDISP_ROTATE_0: case GDISP_ROTATE_180: pdr->x = gdispGGetWidth(m->display) - pdr->x / (4096/gdispGGetWidth(m->display)); pdr->y = pdr->y / (4096/gdispGGetHeight(m->display)); break; case GDISP_ROTATE_90: case GDISP_ROTATE_270: pdr->x = gdispGGetHeight(m->display) - pdr->x / (4096/gdispGGetHeight(m->display)); pdr->y = pdr->y / (4096/gdispGGetWidth(m->display)); break; } #else pdr->x = gdispGGetWidth(m->display) - pdr->x / (4096/gdispGGetWidth(m->display)); pdr->y = pdr->y / (4096/gdispGGetHeight(m->display)); #endif #endif return TRUE; }
bool_t ginputCalibrateMouse(uint16_t instance) { #if !GINPUT_MOUSE_NEED_CALIBRATION (void) instance; return FALSE; #else const coord_t height = gdispGGetHeight(MouseConfig.display); const coord_t width = gdispGGetWidth(MouseConfig.display); #if GINPUT_MOUSE_CALIBRATE_EXTREMES const MousePoint cross[] = {{0, 0}, {(width - 1) , 0}, {(width - 1) , (height - 1)}, {(width / 2), (height / 2)}}; /* Check point */ #else const MousePoint cross[] = {{(width / 4), (height / 4)}, {(width - (width / 4)) , (height / 4)}, {(width - (width / 4)) , (height - (height / 4))}, {(width / 2), (height / 2)}}; /* Check point */ #endif MousePoint points[GINPUT_MOUSE_CALIBRATION_POINTS]; const MousePoint *pc; MousePoint *pt; int32_t px, py; unsigned i, j; font_t font1, font2; #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0 unsigned err; #endif if (instance || (MouseConfig.flags & FLG_IN_CAL)) return FALSE; font1 = gdispOpenFont(GINPUT_MOUSE_CALIBRATION_FONT); font2 = gdispOpenFont(GINPUT_MOUSE_CALIBRATION_FONT2); MouseConfig.flags |= FLG_IN_CAL; gtimerStop(&MouseTimer); MouseConfig.flags &= ~(FLG_CAL_OK|FLG_CAL_SAVED|FLG_CAL_RAW); #if GDISP_NEED_CLIP gdispGSetClip(MouseConfig.display, 0, 0, width, height); #endif #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0 while(1) { #endif gdispGClear(MouseConfig.display, Blue); gdispGFillStringBox(MouseConfig.display, 0, 5, width, 30, GINPUT_MOUSE_CALIBRATION_TEXT, font1, White, Blue, justifyCenter); for(i = 0, pt = points, pc = cross; i < GINPUT_MOUSE_CALIBRATION_POINTS; i++, pt++, pc++) { _tsDrawCross(pc); do { /* Wait for the mouse to be pressed */ while(get_raw_reading(&MouseConfig.t), !(MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT)) gfxSleepMilliseconds(20); /* Average all the samples while the mouse is down */ for(px = py = 0, j = 0; gfxSleepMilliseconds(20), /* Settling time between readings */ get_raw_reading(&MouseConfig.t), (MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT); j++) { px += MouseConfig.t.x; py += MouseConfig.t.y; } } while(!j); pt->x = px / j; pt->y = py / j; _tsClearCross(pc); if (i >= 1 && pt->x == (pt-1)->x && pt->y == (pt-1)->y) { gdispGFillStringBox(MouseConfig.display, 0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_SAME_TEXT, font2, Red, Yellow, justifyCenter); gfxSleepMilliseconds(5000); gdispGFillArea(MouseConfig.display, 0, 35, width, 40, Blue); } } /* Apply 3 point calibration algorithm */ _tsDo3PointCalibration(cross, points, MouseConfig.display, &MouseConfig.caldata); /* Verification of correctness of calibration (optional) : * See if the 4th point (Middle of the screen) coincides with the calibrated * result. If point is within +/- Squareroot(ERROR) pixel margin, then successful calibration * Else, start from the beginning. */ #if GINPUT_MOUSE_MAX_CALIBRATION_ERROR >= 0 /* Transform the co-ordinates */ MouseConfig.t.x = points[3].x; MouseConfig.t.y = points[3].y; _tsTransform(&MouseConfig.t, &MouseConfig.caldata); _tsOrientClip(&MouseConfig.t, MouseConfig.display, FALSE); /* Calculate the delta */ err = (MouseConfig.t.x - cross[3].x) * (MouseConfig.t.x - cross[3].x) + (MouseConfig.t.y - cross[3].y) * (MouseConfig.t.y - cross[3].y); if (err <= GINPUT_MOUSE_MAX_CALIBRATION_ERROR * GINPUT_MOUSE_MAX_CALIBRATION_ERROR) break; gdispGFillStringBox(MouseConfig.display, 0, 35, width, 40, GINPUT_MOUSE_CALIBRATION_ERROR_TEXT, font2, Red, Yellow, justifyCenter); gfxSleepMilliseconds(5000); } #endif // Restart everything gdispCloseFont(font1); gdispCloseFont(font2); MouseConfig.flags |= FLG_CAL_OK; MouseConfig.last_buttons = 0; get_calibrated_reading(&MouseConfig.t); MouseConfig.flags &= ~FLG_IN_CAL; if ((MouseConfig.flags & FLG_INIT_DONE)) gtimerStart(&MouseTimer, MousePoll, 0, TRUE, GINPUT_MOUSE_POLL_PERIOD); // Save the calibration data (if possible) if (MouseConfig.fnsavecal) { MouseConfig.fnsavecal(instance, (const uint8_t *)&MouseConfig.caldata, sizeof(MouseConfig.caldata)); MouseConfig.flags |= FLG_CAL_SAVED; } // Clear the screen using the GWIN default background color #if GFX_USE_GWIN gdispGClear(MouseConfig.display, gwinGetDefaultBgColor()); #else gdispGClear(MouseConfig.display, Black); #endif return TRUE; #endif }
static inline void _tsDo3PointCalibration(const MousePoint *cross, const MousePoint *points, GDisplay *g, Calibration *c) { float dx; coord_t c0, c1, c2; #if GDISP_NEED_CONTROL /* Convert all cross points back to GDISP_ROTATE_0 convention * before calculating the calibration matrix. */ switch(gdispGGetOrientation(g)) { case GDISP_ROTATE_90: c0 = cross[0].y; c1 = cross[1].y; c2 = cross[2].y; break; case GDISP_ROTATE_180: c0 = c1 = c2 = gdispGGetWidth(g) - 1; c0 -= cross[0].x; c1 -= cross[1].x; c2 -= cross[2].x; break; case GDISP_ROTATE_270: c0 = c1 = c2 = gdispGGetHeight(g) - 1; c0 -= cross[0].y; c1 -= cross[1].y; c2 -= cross[2].y; break; case GDISP_ROTATE_0: default: c0 = cross[0].x; c1 = cross[1].x; c2 = cross[2].x; break; } #else (void) g; c0 = cross[0].x; c1 = cross[1].x; c2 = cross[2].x; #endif /* Compute all the required determinants */ dx = (float)(points[0].x - points[2].x) * (float)(points[1].y - points[2].y) - (float)(points[1].x - points[2].x) * (float)(points[0].y - points[2].y); c->ax = ((float)(c0 - c2) * (float)(points[1].y - points[2].y) - (float)(c1 - c2) * (float)(points[0].y - points[2].y)) / dx; c->bx = ((float)(c1 - c2) * (float)(points[0].x - points[2].x) - (float)(c0 - c2) * (float)(points[1].x - points[2].x)) / dx; c->cx = (c0 * ((float)points[1].x * (float)points[2].y - (float)points[2].x * (float)points[1].y) - c1 * ((float)points[0].x * (float)points[2].y - (float)points[2].x * (float)points[0].y) + c2 * ((float)points[0].x * (float)points[1].y - (float)points[1].x * (float)points[0].y)) / dx; #if GDISP_NEED_CONTROL switch(gdispGGetOrientation(g)) { case GDISP_ROTATE_90: c0 = c1 = c2 = gdispGGetWidth(g) - 1; c0 -= cross[0].x; c1 -= cross[1].x; c2 -= cross[2].x; break; case GDISP_ROTATE_180: c0 = c1 = c2 = gdispGGetHeight(g) - 1; c0 -= cross[0].y; c1 -= cross[1].y; c2 -= cross[2].y; break; case GDISP_ROTATE_270: c0 = cross[0].x; c1 = cross[1].x; c2 = cross[2].x; break; case GDISP_ROTATE_0: default: c0 = cross[0].y; c1 = cross[1].y; c2 = cross[2].y; break; } #else c0 = cross[0].y; c1 = cross[1].y; c2 = cross[2].y; #endif c->ay = ((float)(c0 - c2) * (float)(points[1].y - points[2].y) - (float)(c1 - c2) * (float)(points[0].y - points[2].y)) / dx; c->by = ((float)(c1 - c2) * (float)(points[0].x - points[2].x) - (float)(c0 - c2) * (float)(points[1].x - points[2].x)) / dx; c->cy = (c0 * ((float)points[1].x * (float)points[2].y - (float)points[2].x * (float)points[1].y) - c1 * ((float)points[0].x * (float)points[2].y - (float)points[2].x * (float)points[0].y) + c2 * ((float)points[0].x * (float)points[1].y - (float)points[1].x * (float)points[0].y)) / dx; }
static void WM_Move(GHandle gh, coord_t x, coord_t y) { coord_t u, v; #if GWIN_NEED_CONTAINERS if (gh->parent) { // Clip to the parent size u = gh->parent->width - ((const gcontainerVMT *)gh->parent->vmt)->LeftBorder(gh->parent) - ((const gcontainerVMT *)gh->parent->vmt)->RightBorder(gh->parent); v = gh->parent->height - ((const gcontainerVMT *)gh->parent->vmt)->TopBorder(gh->parent) - ((const gcontainerVMT *)gh->parent->vmt)->BottomBorder(gh->parent); } else #endif { // Clip to the screen u = gdispGGetWidth(gh->display); v = gdispGGetHeight(gh->display); } // Make sure we are positioned in the appropriate area if (x+gh->width > u) x = u-gh->width; if (x < 0) x = 0; if (y+gh->height > v) y = v-gh->height; if (y < 0) y = 0; // Make sure we don't overflow the appropriate area u -= x; v -= y; if (gh->width < u) u = gh->width; if (gh->height < v) v = gh->height; if (u != gh->width || v != gh->height) WM_Size(gh, u, v); #if GWIN_NEED_CONTAINERS if (gh->parent) { // Convert to a screen relative position x += gh->parent->x + ((const gcontainerVMT *)gh->parent->vmt)->LeftBorder(gh->parent); y += gh->parent->y + ((const gcontainerVMT *)gh->parent->vmt)->TopBorder(gh->parent); } #endif // If there has been no move just exit if (gh->x == x && gh->y == y) return; // Clear the old area and then redraw if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { // We need to make this window invisible and ensure that has been drawn gwinSetVisible(gh, FALSE); _gwinFlushRedraws(REDRAW_WAIT); // Do the move u = gh->x; gh->x = x; v = gh->y; gh->y = y; #if GWIN_NEED_CONTAINERS // Any children need to be moved if ((gh->flags & GWIN_FLG_CONTAINER)) { GHandle child; // Move to their old relative location. THe WM_Move() will adjust as necessary for(child = gwinGetFirstChild(gh); child; child = gwinGetSibling(child)) WM_Move(child, child->x-u-((const gcontainerVMT *)gh->vmt)->LeftBorder(gh), child->y-v-((const gcontainerVMT *)gh->vmt)->TopBorder(gh)); } #endif gwinSetVisible(gh, TRUE); } else { u = gh->x; gh->x = x; v = gh->y; gh->y = y; #if GWIN_NEED_CONTAINERS // Any children need to be moved if ((gh->flags & GWIN_FLG_CONTAINER)) { GHandle child; // Move to their old relative location. THe WM_Move() will adjust as necessary for(child = gwinGetFirstChild(gh); child; child = gwinGetSibling(child)) WM_Move(child, child->x-u-((const gcontainerVMT *)gh->vmt)->LeftBorder(gh), child->y-v-((const gcontainerVMT *)gh->vmt)->TopBorder(gh)); } #endif } }
static void WM_Size(GHandle gh, coord_t w, coord_t h) { coord_t v; #if GWIN_NEED_CONTAINERS if (gh->parent) { // Clip to the container v = gh->parent->x + gh->parent->width - ((const gcontainerVMT *)gh->parent->vmt)->RightBorder(gh->parent); if (gh->x+w > v) w = v - gh->x; v = gh->parent->y + gh->parent->height - ((const gcontainerVMT *)gh->parent->vmt)->BottomBorder(gh->parent); if (gh->y+h > v) h = v - gh->y; } #endif // Clip to the screen v = gdispGGetWidth(gh->display); if (gh->x+w > v) w = v - gh->x; v = gdispGGetHeight(gh->display); if (gh->y+h > v) h = v - gh->y; // Give it a minimum size if (w < MIN_WIN_WIDTH) w = MIN_WIN_WIDTH; if (h < MIN_WIN_HEIGHT) h = MIN_WIN_HEIGHT; // If there has been no resize just exit if (gh->width == w && gh->height == h) return; // Set the new size and redraw if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { if (w >= gh->width && h >= gh->height) { // The new size is larger - just redraw gh->width = w; gh->height = h; _gwinUpdate(gh); } else { // We need to make this window invisible and ensure that has been drawn gwinSetVisible(gh, FALSE); _gwinFlushRedraws(REDRAW_WAIT); // Resize gh->width = w; gh->height = h; #if GWIN_NEED_CONTAINERS // Any children outside the new area need to be moved if ((gh->flags & GWIN_FLG_CONTAINER)) { GHandle child; // Move to their old relative location. THe WM_Move() will adjust as necessary for(child = gwinGetFirstChild(gh); child; child = gwinGetSibling(child)) WM_Move(child, child->x-gh->x-((const gcontainerVMT *)gh->vmt)->LeftBorder(gh), child->y-gh->y-((const gcontainerVMT *)gh->vmt)->TopBorder(gh)); } #endif // Mark it visible again in its new location gwinSetVisible(gh, TRUE); } } else { gh->width = w; gh->height = h; #if GWIN_NEED_CONTAINERS // Any children outside the new area need to be moved if ((gh->flags & GWIN_FLG_CONTAINER)) { GHandle child; // Move to their old relative location. THe WM_Move() will adjust as necessary for(child = gwinGetFirstChild(gh); child; child = gwinGetSibling(child)) WM_Move(child, child->x-gh->x-((const gcontainerVMT *)gh->vmt)->LeftBorder(gh), child->y-gh->y-((const gcontainerVMT *)gh->vmt)->TopBorder(gh)); } #endif } }