/** * nCapture - Screenshots for TI-Nspire * Copyright (C) 2013 Levak * mail: levak92@gmail.com * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ #include #include #include "nframe.h" #include "nGC.h" #include "syscall.h" #include "bmpfile.h" #define PREVIEW_WIDTH 200 #define PREVIEW_HEIGHT 150 /* Singletons */ static bmpfile_t* bmp = NULL; static Frame frame; static char name[256]; static char folder[256]; /* Mutex */ static char mutex_frame_visible = 0; /* To prevent multiple calls */ static char mutex_close = 0; /* To prevent send popup to segfault */ static char mutex_install = 0; /* To prevent screen shoots to fail on install */ inline rgb_pixel_t getPixel(int x, int y) { unsigned short c = 0; rgb_pixel_t pixel = {0, 0, 0, 0}; if(is_cx) { c = *((unsigned short*)(SCREEN_BASE_ADDRESS + (x << 1) + (y << 9) + (y << 7))); pixel.red = (c >> 11) << 3; pixel.green = (c >> 5) << 2; pixel.blue = ((c & 0x1F) << 3); } else { unsigned char* p = (unsigned char*)(SCREEN_BASE_ADDRESS + ((x >> 1) + (y << 7) + (y << 5))); c = ((x & 1) ? (*p & 0x0F) : (*p >> 4)); c = (c << 4) | c; pixel.red = c; pixel.green = c; pixel.blue = c; } return pixel; } inline void screenshot() { if (!bmp) bmp = bmp_create(SCREEN_WIDTH, SCREEN_HEIGHT, is_cx ? 24 : 4); if (bmp) { int i, j; for (i = 0; i < SCREEN_WIDTH; ++i) for (j = 0; j < SCREEN_HEIGHT; ++j) bmp_set_pixel(bmp, i, j, getPixel(i, j)); } } void capture_preview_painter(Button button, Gc gc, EventCodeGC eventCode) { int w = PREVIEW_WIDTH; int h = PREVIEW_HEIGHT; if (bmp) { int i, j; for (i = 0; i < w; ++i) for (j = 0; j < h; ++j) { rgb_pixel_t* pixel = bmp_get_pixel(bmp, (i*SCREEN_WIDTH)/w, (j*SCREEN_HEIGHT)/h); gui_gc_setColorRGB(gc, pixel->red, pixel->green, pixel->blue); gui_gc_fillRect(gc, i, j, 1, 1); } } else { gui_gc_setColorRGB(gc, 255, 255, 255); gui_gc_fillRect(gc, 0, 0, w, h); } } void saveas_fun(Button button, CallbackData button_data, EventCode eventCode) { if(eventCode == ENTER || eventCode == MOUSECLIC) { if(show_save_dialog(0, folder, name, 0, 0) == 0x13EF) { char* path = calloc(1, sizeof(char) * (strlen(name) + strlen(folder) + 1 + 11 + 4)); strcpy(path, "/documents/"); strcat(path, folder); strcat(path, name); strcat(path, ".tns"); puts(path); bmp_save(bmp, path); } } } void close_fun(Button button, CallbackData button_data, EventCode eventCode) { if(eventCode == ENTER || eventCode == MOUSECLIC) { mutex_frame_visible = 0; gui_Frame_setVisible(frame, 0); bmp_destroy(bmp); bmp = NULL; mutex_close = 1; } } void open_gui() { screenshot(); if (!frame) { String frame_title = string_new(); string_set_ascii(frame_title, "New capture - nCapture"); char undef_buf[8]; *(char**)undef_buf = "DLG - CAPTURE"; frame = gui_new_Frame_0(0, frame_title->str, 0x11941, 48, DCOL, undef_buf); Container container = gui_getContentPane(frame); /* Preview panel */ Panel panel1 = gui_addNew_Panel(container, 0); gui_Panel_setLayout(panel1, 0x128E6); gui_Panel_setMarginH(panel1, 5, 5); gui_Panel_setMarginV(panel1, 8, 5); gui_Panel_setGridMargin(panel1, 0, 0); /* Capture preview */ Button preview = gui_addNew_CustomButton(panel1, 0, 0, 0, 0, HLEFT, VCENTER, 0, 0, capture_preview_painter, -1, 1); gui_Component_setMaxSize(preview, PREVIEW_WIDTH, PREVIEW_HEIGHT); gui_Button_setTabable(preview, UNTABABLE); gui_addNew_Separator(container); /* Bottom buttons panel */ Panel panel_b = gui_addNew_Panel(container, 0); gui_Panel_setLayout(panel_b, 0x128E3); gui_Panel_setMarginV(panel_b, 5, 0); gui_Panel_setGridMargin(panel_b, 0, 0); /* Invisible Button - Close */ Button close = gui_addNew_Button_0(panel_b, 0, 0, 0, 0, HLEFT, VCENTER, 0, close_fun); gui_Button_setTabable(close, UNTABABLE); /* Button - Save as */ Button saveas = gui_addNew_Button_0(panel_b, 0, 0x4C, SYST, get_res_string(SYST, 0x15), HRIGHT, VCENTER, 0, saveas_fun); gui_Frame_setSelectedObject(frame, saveas); gui_Frame_setEscListener(frame, close); } if (mutex_frame_visible) { gui_Frame_invalidate(frame); mutex_close = 1; } else { mutex_frame_visible = 1; gui_Frame_setVisible(frame, 1); } } HOOK_DEFINE(hook_ctrl) { unsigned int* r5 = (unsigned int*)HOOK_SAVED_REGS(hook_ctrl)[5]; if (*r5 == 0x3E && !mutex_install) { mutex_close = 0; open_gui(); if (mutex_frame_visible || !mutex_close) { if (!mutex_close) mutex_frame_visible = 0; HOOK_RESTORE_RETURN(hook_ctrl); } else { /* Manual context restore */ __asm volatile("ADD SP, SP, #0x48"); /* We do want to skip the event */ end_event(); /* so we jump directly to the end of the function/stack */ } } else HOOK_RESTORE_RETURN(hook_ctrl); } void main() { /* If hook isn't already installed */ if(*((int*)HOOK_ADDR) == HOOK_VALUE) { /* Install hook */ mutex_install = 1; strcpy(name, "capture.bmp"); strcpy(folder, "/"); HOOK_INSTALL(HOOK_ADDR, hook_ctrl); nl_set_resident(); if(!nl_isstartup()) { show_msgbox("nCapture says", "nCapture has been successfuly installed on your TI-Nspire !\n" "You can now take screen shots using CTRL+.\n" "Move nCapture.tns into /ndless/startup/ if you want nCapture to patch the OS on startup !\n" "Levak"); } mutex_install = 0; } else { show_msgbox("nCapture says", "nCapture is already hooked !\nUse Ctrl+. to take a screenshot."); } }