// The reading callback function static void DialCallback(uint16_t instance, uint16_t rawvalue) { struct DialStatus_t *pds; GSourceListener *psl; GEventDial *pe; /* Get the information we need */ pds = DialStatus+instance; /* Range scale - if needed */ if (pds->max != GINPUT_DIAL_MAX_VALUE) rawvalue = (uint16_t)((uint32_t)rawvalue * pds->max / GINPUT_DIAL_MAX_VALUE); /* Forget about changes below our sensitivity threshold */ if (rawvalue >= pds->lastvalue) { if (rawvalue - pds->lastvalue < pds->sensitivity) return; } else { if (pds->lastvalue - rawvalue < pds->sensitivity) return; } /* Save the value */ pds->lastvalue = rawvalue; // Send the event to the listeners that are interested. psl = 0; while ((psl = geventGetSourceListener((GSourceHandle)(DialStatus+instance), psl))) { if (!(pe = (GEventDial *)geventGetEventBuffer(psl))) continue; pe->type = GEVENT_DIAL; pe->instance = instance; pe->value = pds->lastvalue; geventSendEvent(psl); } }
static void SendMouseEvent(GSourceListener *psl, GMouse *m, GMouseReading *r) { GEventMouse *pe; // If there is no event buffer just mark a missed event if (!(pe = (GEventMouse *)geventGetEventBuffer(psl))) { // This listener is missing - save the meta events that have happened psl->srcflags |= ((r->buttons & GMETA_MASK)|GINPUT_MISSED_MOUSE_EVENT); return; } // If we haven't really moved (and there are no meta events) don't bother sending the event if (!(r->buttons & GMETA_MASK) && !psl->srcflags && !(psl->listenflags & GLISTEN_MOUSENOFILTER) && r->x == m->r.x && r->y == m->r.y && (r->buttons & GINPUT_MOUSE_BTN_MASK) == (m->r.buttons & GINPUT_MOUSE_BTN_MASK)) return; // Send the event only if we are listening for it if (!((r->buttons & GINPUT_MOUSE_BTN_LEFT) && (psl->listenflags & GLISTEN_MOUSEDOWNMOVES)) && !(!(r->buttons & GINPUT_MOUSE_BTN_LEFT) && (psl->listenflags & GLISTEN_MOUSEUPMOVES)) && !((r->buttons & GMETA_MASK) && (psl->listenflags & GLISTEN_MOUSEMETA))) return; #if !GINPUT_TOUCH_NOTOUCH pe->type = (gmvmt(m)->d.flags & GMOUSE_VFLG_TOUCH) ? GEVENT_TOUCH : GEVENT_MOUSE; #else pe->type = GEVENT_MOUSE; #endif pe->x = r->x; pe->y = r->y; pe->z = r->z; pe->buttons = r->buttons | psl->srcflags; psl->srcflags = 0; pe->display = m->display; geventSendEvent(psl); }
void _gwinSendEvent(GHandle gh, GEventType type) { GSourceListener * psl; GEventGWin * pge; // Trigger a GWIN Event psl = 0; while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) { if (!(pge = (GEventGWin *)geventGetEventBuffer(psl))) continue; pge->type = type; pge->gwin = gh; #if GWIN_WIDGET_TAGS pge->tag = (gh->flags & GWIN_FLG_WIDGET) ? ((GWidgetObject *)gh)->tag : 0; #endif geventSendEvent(psl); } }
// Send the button event static void SendButtonEvent(GWidgetObject *gw) { GSourceListener * psl; GEvent * pe; #define pbe ((GEventGWinButton *)pe) // Trigger a GWIN Button Event psl = 0; while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) { if (!(pe = geventGetEventBuffer(psl))) continue; pbe->type = GEVENT_GWIN_BUTTON; pbe->button = (GHandle)gw; geventSendEvent(psl); } #undef pbe }
// Send the checkbox event static void SendCheckboxEvent(GWidgetObject *gw) { GSourceListener * psl; GEvent * pe; #define pce ((GEventGWinCheckbox *)pe) // Trigger a GWIN Checkbox Event psl = 0; while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) { if (!(pe = geventGetEventBuffer(psl))) continue; pce->type = GEVENT_GWIN_CHECKBOX; pce->checkbox = &gw->g; pce->isChecked = (gw->g.flags & GCHECKBOX_FLG_CHECKED) ? TRUE : FALSE; geventSendEvent(psl); } #undef pce }
static void SendKeyboardEventToListener(GSourceListener *psl, GKeyboard *k) { GEventKeyboard *pe; int i; // If there is no event buffer just mark a missed event if (!(pe = (GEventKeyboard *)geventGetEventBuffer(psl))) { // This listener is missing - save the meta events that have happened psl->srcflags |= GKEYSTATE_MISSED_EVENT; return; } if ((psl->listenflags & GLISTEN_KEYRAW)) { pe->type = GEVENT_KEYBOARD; pe->bytecount = k->cntsc; for(i = 0; i < k->cntsc; i++) pe->c[i] = k->sc[i]; for(; i < 8; i++) pe->c[i] = 0; pe->keystate = k->keystate | psl->srcflags | GKEYSTATE_RAW; psl->srcflags = 0; return; } if ((psl->listenflags & GLISTEN_KEYREPEATSOFF) && (k->keystate & GKEYSTATE_REPEAT)) return; if ((psl->listenflags & GLISTEN_KEYNOSPECIALS) && (k->keystate & GKEYSTATE_SPECIAL)) return; if (!(psl->listenflags & GLISTEN_KEYUP) && (k->keystate & GKEYSTATE_KEYUP)) k->cntc = 0; if (!(psl->listenflags & GLISTEN_KEYTRANSITIONS) && !k->cntc) return; pe->type = GEVENT_KEYBOARD; pe->bytecount = k->cntc; for(i = 0; i < k->cntc; i++) pe->c[i] = k->c[i]; for(; i < 8; i++) pe->c[i] = 0; pe->keystate = k->keystate | psl->srcflags; psl->srcflags = 0; geventSendEvent(psl); }
// Send the button event static void SendRadioEvent(GWidgetObject *gw) { GSourceListener * psl; GEvent * pe; #define pbe ((GEventGWinRadio *)pe) // Trigger a GWIN Button Event psl = 0; while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) { if (!(pe = geventGetEventBuffer(psl))) continue; pbe->type = GEVENT_GWIN_RADIO; pbe->gwin = (GHandle)gw; pbe->group = ((GRadioObject *)gw)->group; #if GWIN_WIDGET_TAGS pbe->tag = gw->tag; #endif geventSendEvent(psl); } #undef pbe }
static void sendListEvent(GWidgetObject *gw, int item) { GSourceListener* psl; GEvent* pe; // Trigger a GWIN list event psl = 0; while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) { if (!(pe = geventGetEventBuffer(psl))) continue; ple->type = GEVENT_GWIN_LIST; ple->gwin = (GHandle)gw; ple->item = item; #if GWIN_WIDGET_TAGS ple->tag = gw->tag; #endif geventSendEvent(psl); } }
static void HighSpeedGTimerCallback(void *param) { (void) param; GSourceListener *psl; GEventADC *pe; psl = 0; while ((psl = geventGetSourceListener((GSourceHandle)(&HighSpeedGTimer), psl))) { if (!(pe = (GEventADC *)geventGetEventBuffer(psl))) { // This listener is missing - save this. psl->srcflags |= GADC_HSADC_LOSTEVENT; continue; } pe->type = GEVENT_ADC; pe->count = hs.lastcount; pe->buffer = hs.lastbuffer; pe->flags = hs.lastflags | psl->srcflags; psl->srcflags = 0; geventSendEvent(psl); } }
static void AudGTimerCallback(void *param) { (void) param; GSourceListener *psl; GEventADC *pe; psl = 0; while ((psl = geventGetSourceListener((GSourceHandle)(&aud), psl))) { if (!(pe = (GEventAudioIn *)geventGetEventBuffer(psl))) { // This listener is missing - save this. psl->srcflags |= GADC_AUDIO_IN_LOSTEVENT; continue; } pe->type = GEVENT_AUDIO_IN; pe->channel = aud.channel; pe->count = lastcount; pe->buffer = lastbuffer; pe->flags = psl->srcflags; psl->srcflags = 0; geventSendEvent(psl); } }
static void MousePoll(void *param) { (void) param; GSourceListener *psl; GEventMouse *pe; unsigned meta; uint16_t tbtns; uint32_t cdiff; uint32_t mdiff; // Save the last mouse state MouseConfig.last_buttons = MouseConfig.t.buttons; // Get the new mouse reading get_calibrated_reading(&MouseConfig.t); // Calculate out new event meta value and handle CLICK and CXTCLICK meta = GMETA_NONE; // Calculate the position difference from our movement reference (update the reference if out of range) mdiff = (MouseConfig.t.x - MouseConfig.movepos.x) * (MouseConfig.t.x - MouseConfig.movepos.x) + (MouseConfig.t.y - MouseConfig.movepos.y) * (MouseConfig.t.y - MouseConfig.movepos.y); if (mdiff > GINPUT_MOUSE_MAX_MOVE_JITTER * GINPUT_MOUSE_MAX_MOVE_JITTER) { MouseConfig.movepos.x = MouseConfig.t.x; MouseConfig.movepos.y = MouseConfig.t.y; } // Check if the click has moved outside the click area and if so cancel the click if ((MouseConfig.flags & FLG_CLICK_TIMER)) { cdiff = (MouseConfig.t.x - MouseConfig.clickpos.x) * (MouseConfig.t.x - MouseConfig.clickpos.x) + (MouseConfig.t.y - MouseConfig.clickpos.y) * (MouseConfig.t.y - MouseConfig.clickpos.y); if (cdiff > GINPUT_MOUSE_MAX_CLICK_JITTER * GINPUT_MOUSE_MAX_CLICK_JITTER) MouseConfig.flags &= ~FLG_CLICK_TIMER; } // Mouse down tbtns = MouseConfig.t.buttons & ~MouseConfig.last_buttons; if ((tbtns & GINPUT_MOUSE_BTN_LEFT)) meta |= GMETA_MOUSE_DOWN; if ((tbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT))) { MouseConfig.clickpos.x = MouseConfig.t.x; MouseConfig.clickpos.y = MouseConfig.t.y; MouseConfig.clicktime = chTimeNow(); MouseConfig.flags |= FLG_CLICK_TIMER; } // Mouse up tbtns = ~MouseConfig.t.buttons & MouseConfig.last_buttons; if ((tbtns & GINPUT_MOUSE_BTN_LEFT)) meta |= GMETA_MOUSE_UP; if ((tbtns & (GINPUT_MOUSE_BTN_LEFT|GINPUT_MOUSE_BTN_RIGHT))) { if ((MouseConfig.flags & FLG_CLICK_TIMER)) { if ((tbtns & GINPUT_MOUSE_BTN_LEFT) #if GINPUT_MOUSE_CLICK_TIME != TIME_INFINITE && chTimeNow() - MouseConfig.clicktime < MS2ST(GINPUT_MOUSE_CLICK_TIME) #endif ) meta |= GMETA_MOUSE_CLICK; else meta |= GMETA_MOUSE_CXTCLICK; MouseConfig.flags &= ~FLG_CLICK_TIMER; } } // Send the event to the listeners that are interested. psl = 0; while ((psl = geventGetSourceListener((GSourceHandle)(&MouseConfig), psl))) { if (!(pe = (GEventMouse *)geventGetEventBuffer(psl))) { // This listener is missing - save the meta events that have happened psl->srcflags |= meta; continue; } // If we haven't really moved (and there are no meta events) don't bother sending the event if (mdiff <= GINPUT_MOUSE_MAX_MOVE_JITTER * GINPUT_MOUSE_MAX_MOVE_JITTER && !psl->srcflags && !meta && !(psl->listenflags & GLISTEN_MOUSENOFILTER)) continue; // Send the event if we are listening for it if (((MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT) && (psl->listenflags & GLISTEN_MOUSEDOWNMOVES)) || (!(MouseConfig.t.buttons & GINPUT_MOUSE_BTN_LEFT) && (psl->listenflags & GLISTEN_MOUSEUPMOVES)) || (meta && (psl->listenflags & GLISTEN_MOUSEMETA))) { pe->type = GINPUT_MOUSE_EVENT_TYPE; pe->instance = 0; pe->x = MouseConfig.t.x; pe->y = MouseConfig.t.y; pe->z = MouseConfig.t.z; pe->current_buttons = MouseConfig.t.buttons; pe->last_buttons = MouseConfig.last_buttons; pe->meta = meta; if (psl->srcflags) { pe->current_buttons |= GINPUT_MISSED_MOUSE_EVENT; pe->meta |= psl->srcflags; psl->srcflags = 0; } geventSendEvent(psl); } } }
static DECLARE_THREAD_FUNCTION(visualizerThread, arg) { (void)arg; GListener event_listener; geventListenerInit(&event_listener); geventAttachSource(&event_listener, (GSourceHandle)¤t_status, 0); visualizer_keyboard_status_t initial_status = { .default_layer = 0xFFFFFFFF, .layer = 0xFFFFFFFF, .mods = 0xFF, .leds = 0xFFFFFFFF, .suspended = false, }; visualizer_state_t state = { .status = initial_status, .current_lcd_color = 0, #ifdef LCD_ENABLE .font_fixed5x8 = gdispOpenFont("fixed_5x8"), .font_dejavusansbold12 = gdispOpenFont("DejaVuSansBold12") #endif }; initialize_user_visualizer(&state); state.prev_lcd_color = state.current_lcd_color; #ifdef LCD_BACKLIGHT_ENABLE lcd_backlight_color( LCD_HUE(state.current_lcd_color), LCD_SAT(state.current_lcd_color), LCD_INT(state.current_lcd_color)); #endif systemticks_t sleep_time = TIME_INFINITE; systemticks_t current_time = gfxSystemTicks(); while(true) { systemticks_t new_time = gfxSystemTicks(); systemticks_t delta = new_time - current_time; current_time = new_time; bool enabled = visualizer_enabled; if (!same_status(&state.status, ¤t_status)) { if (visualizer_enabled) { if (current_status.suspended) { stop_all_keyframe_animations(); visualizer_enabled = false; state.status = current_status; user_visualizer_suspend(&state); } else { state.status = current_status; update_user_visualizer_state(&state); } state.prev_lcd_color = state.current_lcd_color; } } if (!enabled && state.status.suspended && current_status.suspended == false) { // Setting the status to the initial status will force an update // when the visualizer is enabled again state.status = initial_status; state.status.suspended = false; stop_all_keyframe_animations(); user_visualizer_resume(&state); state.prev_lcd_color = state.current_lcd_color; } sleep_time = TIME_INFINITE; for (int i=0;i<MAX_SIMULTANEOUS_ANIMATIONS;i++) { if (animations[i]) { update_keyframe_animation(animations[i], &state, delta, &sleep_time); } } #ifdef LED_ENABLE gdispGFlush(LED_DISPLAY); #endif #ifdef EMULATOR draw_emulator(); #endif // The animation can enable the visualizer // And we might need to update the state when that happens // so don't sleep if (enabled != visualizer_enabled) { sleep_time = 0; } systemticks_t after_update = gfxSystemTicks(); unsigned update_delta = after_update - current_time; if (sleep_time != TIME_INFINITE) { if (sleep_time > update_delta) { sleep_time -= update_delta; } else { sleep_time = 0; } } dprintf("Update took %d, last delta %d, sleep_time %d\n", update_delta, delta, sleep_time); #ifdef PROTOCOL_CHIBIOS // The gEventWait function really takes milliseconds, even if the documentation says ticks. // Unfortunately there's no generic ugfx conversion from system time to milliseconds, // so let's do it in a platform dependent way. // On windows the system ticks is the same as milliseconds anyway if (sleep_time != TIME_INFINITE) { sleep_time = ST2MS(sleep_time); } #endif geventEventWait(&event_listener, sleep_time); } #ifdef LCD_ENABLE gdispCloseFont(state.font_fixed5x8); gdispCloseFont(state.font_dejavusansbold12); #endif return 0; } void visualizer_init(void) { gfxInit(); #ifdef LCD_BACKLIGHT_ENABLE lcd_backlight_init(); #endif #ifdef SERIAL_LINK_ENABLE add_remote_objects(remote_objects, sizeof(remote_objects) / sizeof(remote_object_t*) ); #endif #ifdef LCD_ENABLE LCD_DISPLAY = get_lcd_display(); #endif #ifdef LED_ENABLE LED_DISPLAY = get_led_display(); #endif // We are using a low priority thread, the idea is to have it run only // when the main thread is sleeping during the matrix scanning gfxThreadCreate(visualizerThreadStack, sizeof(visualizerThreadStack), VISUALIZER_THREAD_PRIORITY, visualizerThread, NULL); } void update_status(bool changed) { if (changed) { GSourceListener* listener = geventGetSourceListener((GSourceHandle)¤t_status, NULL); if (listener) { geventSendEvent(listener); } } #ifdef SERIAL_LINK_ENABLE static systime_t last_update = 0; systime_t current_update = chVTGetSystemTimeX(); systime_t delta = current_update - last_update; if (changed || delta > MS2ST(10)) { last_update = current_update; visualizer_keyboard_status_t* r = begin_write_current_status(); *r = current_status; end_write_current_status(); } #endif } uint8_t visualizer_get_mods() { uint8_t mods = get_mods(); #ifndef NO_ACTION_ONESHOT if (!has_oneshot_mods_timed_out()) { mods |= get_oneshot_mods(); } #endif return mods; } void visualizer_update(uint32_t default_state, uint32_t state, uint8_t mods, uint32_t leds) { // Note that there's a small race condition here, the thread could read // a state where one of these are set but not the other. But this should // not really matter as it will be fixed during the next loop step. // Alternatively a mutex could be used instead of the volatile variables bool changed = false; #ifdef SERIAL_LINK_ENABLE if (is_serial_link_connected ()) { visualizer_keyboard_status_t* new_status = read_current_status(); if (new_status) { if (!same_status(¤t_status, new_status)) { changed = true; current_status = *new_status; } } } else { #else { #endif visualizer_keyboard_status_t new_status = { .layer = state, .default_layer = default_state, .mods = mods, .leds = leds, .suspended = current_status.suspended, }; if (!same_status(¤t_status, &new_status)) { changed = true; current_status = new_status; } } update_status(changed); } void visualizer_suspend(void) { current_status.suspended = true; update_status(true); } void visualizer_resume(void) { current_status.suspended = false; update_status(true); }
static void mouseDown(GWidgetObject *gw, coord_t mx, coord_t my) { GHandle ph, gh; int cnt; if (my < 0 || my > ((GTabsetObject *)gw)->border_top) return; // Work out which tab was pressed { coord_t x, w, y; cnt = 0; x = w = 0; y = GWIN_TABSET_TABHEIGHT; gh = 0; for(ph = gwinGetFirstChild(&gw->g); ph; ph = gwinGetSibling(ph)) { if (ph->vmt == (gwinVMT *)&tabpageVMT) { w = gdispGetStringWidth(((GWidgetObject *)ph)->text, gw->g.font) + TEXT_PADDING*2; x += w; if (x > gw->g.width) { y += GWIN_TABSET_TABHEIGHT; x = w; } if (my < y && mx < x) { gh = ph; break; } cnt++; } } if (!gh || (gh->flags & GWIN_FLG_VISIBLE)) return; } // Mark the existing tab as not visible for(ph = gwinGetFirstChild(&gw->g); ph; ph = gwinGetSibling(ph)) { if (ph->vmt == (gwinVMT *)&tabpageVMT && (ph->flags & GWIN_FLG_VISIBLE)) { // Mark this page invisible ph->flags &= ~GWIN_FLG_VISIBLE; break; } } // Mark this tab as visible gh->flags |= GWIN_FLG_VISIBLE; _gwinRippleVisibility(); // Force a redraw of the whole tabset _gwinUpdate(&gw->g); // Send the Tabset Event { GSourceListener * psl; GEventGWinTabset * pge; psl = 0; while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) { if (!(pge = (GEventGWinTabset *)geventGetEventBuffer(psl))) continue; pge->type = GEVENT_GWIN_TABSET; pge->gwin = &gw->g; #if GWIN_WIDGET_TAGS pge->tag = gw->tag; #endif pge->ghPage = gh; pge->nPage = cnt; geventSendEvent(psl); } } }