Xwork's Blog

The lord is waiting to take your hand.

Feliz 2019

No hay comentarios.
Hola de nuevo a todos, el día de hoy solo escribo para desearles un feliz año 2019, cómo de costumbre, el año que viene publicaré mas y mas post que espero que sean de utilidad para el que los lee.

Sin nada mas que decir, FELIZ 2019!!!
Los leo luego.

No hay comentarios. :

Publicar un comentario

Vamos a programar #63 - Actualizando un gadget de windows 7 a windows 10 (parte 2).

No hay comentarios.
Hola de nuevo a todos, el dia de hoy vamos a terminar de modificar el gadget de reloj para usarlo en windows 10. Retomando el post anteror, el dia de hoy vamos a hacer modificaciones al gadget para hacerlo un poco mas a nuestro gusto.

Cambiando la localización.

Usualmente cuando nos referimos a localización, hablamos del idioma en el que estará el programa. Por default, el gadget viene en ingles, pero si queremos cambiarlo al idioma español (o al que sea), para hacer los cambios, debemos de editar el archivo "localization.js" y cambiar todo el contenido por el siguiente (si quieres que el gadget esté en español):


console.log('loaded: localization.js');

var m = ['ENERO','FEBRERO','MARZO','ABRIL','MAYO','JUNIO','JULIO','AGOSTO','SEPTIEMBRE','OCTUBRE','NOVIEMBRE','DICIEMBRE'];
var d = ['DOMINGO','LUNES','MARTES','MIERCOLES','JUEVES','VIERNES','SABADO'];

Básicamente lo que hacemos es escribir los nombres para cada día de la semana y para cada mes, esto no tiene realmente nada de difícil, salvo la parte de escribir los nombres de los días en otros idiomas.

De 12 a 24 horas

Otro de las partes que se puede modificar del gadget, es cómo se muestra la hora, por default el reloj viene en formato de 12 horas, pero además no se muestran lo segundos.

Antes de continuar, hay que resaltar que actualizar la hora a cada segundo, puede traer algunos problemas de rendimiento en algunos equipos, en lo personal, no lo he notado en un equipo medianamente viejo y mucho menos se siente en equipos mas modernos, por lo que si experimentas problemas de rendimiento, debes de cambiar el código para que funcione mejor (o quitar el gadget).
Una vez hecha la advertencia anterior, veamos el código.

console.log('loaded: gadget.js');

var font;
var color;
var opacity;
// var negativeVerticalMargin;
// var negativeHorizontalMargin;

var toTime;
var toDate;
var toMonth;
var toDay;

var targetWidth;
var targetHeight;

function init() {
	console.log('[init]');

	System.Gadget.settingsUI = 'settings.html';
	System.Gadget.onSettingsClosed = function() {
		readSettings();
		createTextObjects();
		refresh(false);
	};

	readSettings();
	createTextObjects();
	refresh(true);
}

function readSettings() {
	console.log('[readSettings]');

	font = System.Gadget.Settings.readString('font') || 'Arial';
	color = System.Gadget.Settings.readString('color') || 'white';
	opacity = System.Gadget.Settings.read('opacity') || 30;
	// negativeVerticalMargin = System.Gadget.Settings.read('negativeVerticalMargin') || 0;
	// negativeHorizontalMargin = System.Gadget.Settings.read('negativeHorizontalMargin') || 0;

	console.log('    font: '+font);
	console.log('    color: '+color);
	console.log('    opacity: '+opacity);
}

function createTextObjects() {
	console.log('[createTextObjects]');

	var bg = document.getElementById('bg');
	bg.removeObjects();

	// 0's are dummy chars for initial text object alignment
	toTime = bg.addTextObject('00:00:00', font, 105, color, 0, 0);
	toDate = bg.addTextObject('0', font, 80, color, toTime.left, 90); //(toTime.top+toTime.height)*0.69);
	toMonth = bg.addTextObject('0', font, 45, color, toDate.left+toDate.width, 95);
	toDay = bg.addTextObject('0', font, 30, color, toDate.left+toDate.width, 135);

	//we really don't want to be changing the width of the gadget because of clock time
	//because gadgets are anchored on the desktop by the left side, and the content is right-aligned

	targetWidth = document.getElementsByTagName('body')[0].style.width = toTime.width;
	targetHeight = document.getElementsByTagName('body')[0].style.height = toDay.top + toDay.height;
}

function refresh(autoreload) {
	console.log('[refresh]');

	console.log('    font: '+font);
	console.log('    color: '+color);
	console.log('    opacity: '+opacity);


	var currentTime = System.Time.getLocalTime(System.Time.currentTimeZone);
	var currentDate = new Date(Date.parse(currentTime));

	var hours = currentDate.getHours();

	var minutes = currentDate.getMinutes();
	minutes = ((minutes < 10) ? ':0' : ':') + minutes;
// Comentar las siguientes dos lineas para no mostrar los segundos
	var seconds = currentDate.getSeconds();
	seconds = ((seconds < 10) ? ':0' : ':') + seconds;
//Quitar los comentarios de la siguiente linea y comentar la siguiente para no mostar los segundos
	//toTime.value = hours + minutes + " HR";
	toTime.value = hours + minutes + seconds;
	toTime.font = font;
	toTime.color = color;
	toTime.opacity = opacity;

	toTime.left = targetWidth - toTime.width;
	toTime.top = 0;


	toDate.value = currentDate.getDate();
	toDate.font = font;
	toDate.color = color;
	toDate.opacity = opacity;

	toDate.left = toTime.left;
	toDate.top = 90; // - negativeVerticalMargin;


	toMonth.value = m[currentDate.getMonth()];
	toMonth.font = font;
	toMonth.color = color;
	toMonth.opacity = opacity;

	toMonth.left = toDate.left + toDate.width;
	// goofly little formula here to goose the month riiiigh up to but not touching the time, for most fonts
	toMonth.top = toDate.top + 4 + (toDate.top * 0.05) ; //95;


	toDay.value = d[currentDate.getDay()];
	toDay.font = font;
	toDay.color = color;
	toDay.opacity = opacity;

	toDay.left = toMonth.left;
	toDay.top = toMonth.top + 41; //135;


	console.log('    width: '+toTime.width+', height: '+toDay.top + toDay.height);
	console.log('    toTime: x='+toTime.left+', y='+toTime.top+', h='+toTime.height+', w='+toTime.width);
	

	if (autoreload) {
		//cuando mostramos los segundos hay que actualizar cada segundo, pero si queremos actualizar cada minutos, debemos hacerlo cada 60
		//en lugar de tener 1*1000, debemos cambiar a 60*1000
		setTimeout(function() { refresh(true); }, 1*1000);
	}
}

Este código es el que vamos a sustituir en el archivo "gadget.js" que es el principal. Con lo anterior, hemos cambiado la presentación de 12 a 24 horas, el código viene comentado para que hagas los cambios que creas necesarios, si te gusta más el formato de 12 horas, bastará con que revises el código fuente del original y el que aquí vimos.

El gadget empaquetado y que luce cómo el de la imagen, lo puedes descargar de mi dropbox y probarlo.

Los leo y luego y feliz 2019!!

No hay comentarios. :

Publicar un comentario

Vamos a programar #62 - Actualizando un gadget de windows 7 a windows 10.

No hay comentarios.
Hola de nuevo a todos, el día de hoy vamos a ver cómo es "posible" actualizar un gadget de Windows 7 para poder usarse en Windows 10.
Cómo muchos sabrán, hago programas para computadora, la mayoría de ellos están diseñados para ejecutarse en computadoras con Windows, pero muy específicamente en computadoras con Windows 7 para abajo. Gracias a que en la mayoria de los programas se usa .NET que se encarga de hacer el trabajo sucio por nosotros si es necesario que la aplicación se ejecute en un sistema operativo superior; llámese windows 10. Pero hace unos días, recibí la solicitud de un programa; mejor dicho; una "app" de windows 10 (y no voy a entrar en detalles por ahora) por lo que me vi en la necesidad de actualizar mi computadora.


La solicitud llegó unos días después, justo cuando había logrado personalizar mi escritorio a mi gusto.
Para hacer memoria, los gadgets son "mini-aplicaciones" basados en html, javascript y varios controles activex mas, estos aparecieron  por primera vez en windows vista y su tiempo de vida solo se prolongo hasta windows 7 (8?), debido a que se encontraron fallas críticas que permitían de manera potencial, permitir el acceso al equipo.

Es posible utilizar los gadgets en windows 10, pero para lograr una experiencia similar a windows 7, es necesario modificarlos, en el caso muy particular del gadget que vamos a modificar, el principal problema eran las fuentes. Solo estaban disponibles las basicas de windows y a pesar de haber instalado varias más, ninguna de éstas se mostraba.

Antes de continuar, si quieres usar el gadget en windows 10, debes de buscar algún programa que permita hacerlo, por cuestiones de seguridad no lo voy a poner aqui, ya que cómo mencioné antes, hay vulnerabilidades que podrían ser explotadas por un tercero. Si aun así quieres continuar, puedes buscar en internet "windows 10 gadgets", luego debes de descargar la version original del gadget desde su sitio web , descargarlo e instalarlo (solo para darle el debido crédito a sus autores, ya que en teoría vamos a reemplazar muchos de los archivos originales, aunque según la licencia, podemos modificarlo a nuestro gusto si no es que todo).

Ahora que ya estan dichas todas las advertencias, procederemos a abrir el gadget con Winrar.
Y extraeremos todo el contenido en una carpeta, una vez hecho buscaremos la carpeta llamada "js" y con un bloc de notas (en mi caso notepad++), abriremos el archivo "font-picker.js" y reemplazaremos su contenido con el siguiente codigo:

/*
Based on Jonathan Abbott's Flip Calendar gadget
http://vistagadgets.spaces.live.com/
*/

console.log('loaded: font-picker.js');

var fontPicker = {
	supportedFontTypes: ' (truetype) ',
	fontsToSkip: ':Bookshelf Symbol 7:'+':MS Outlook:'+':MS Reference Specialty:'+':MT Extra:'+':Symbol:'+':Webdings:'+':Wingdings:'+':Wingdings 2:'+':Wingdings 3:',

	fillYield: 50,	// Yield back to IE every X ms

	fontSizer: null,
	fonttypeIndex: 0,
	currentFont: System.Gadget.document.parentWindow.font,
	selectingFont: -1,

	init: function() {
		console.log('[init]');

		// System.Gadget.onSettingsClosing = this.settingsClosing;

		divFonttype.style.fontFamily = divFonttype.innerText = this.currentFont;
		divFonttype.style.fontSize = '16px';

		this.fontSizer = document.createElement('<g:background />').addTextObject(this.currentFont, this.currentFont, 16, 'black', 0, 0);

		//remove focus from the 1st checkbox
		document.body.focus();
		
		//read the fonts from the registry and build the table
		this.buildList(this.readFonts());

		// setFont(currentFont, 0);
		// console.log(tdFonts);
		// console.log(this.fonttypeIndex);
		tdFonts.rows(this.fonttypeIndex).className = 'menuItemSelected';
	},

	settingsClosing: function(event) {
		console.log('[settingsClosing]');
		
		if (event.closeAction == event.Action.commit) {
			System.Gadget.Settings.writeString('font', divFonttype.innerText);
		}
		// event.cancel = false;
	},

	readFonts: function() {
		console.log('[readFonts]');

		var HKLM = 2147483649 ;
		var rPath = 'SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts';
	

		// connect to the registry
		var oSwbem = new ActiveXObject('WbemScripting.SwbemLocator');
		var oSvc = oSwbem.ConnectServer(null, 'root\\default');
		var oReg = oSvc.Get('StdRegProv');

		// enumerate the values 
		var oMethod = oReg.Methods_.Item('EnumValues');
		var oInParam = oMethod.InParameters.SpawnInstance_();
		oInParam.hDefKey = HKLM;
		oInParam.sSubKeyName = rPath;
		var oOutParam = oReg.ExecMethod_(oMethod.Name, oInParam);

		// get the values into an array
		var sNames = oOutParam.sNames.toArray();

		// sort it
		sNames.sort();

		return sNames;
	},

	buildList: function(listItems) {
		console.log('[buildList]');

		// try{
			var counter = new Date();

			while (listItems.length > 0 && (new Date())-counter<this.fillYield) {
				// is the font one we can use
				var fontType = ' ' + listItems[0].substring(listItems[0].lastIndexOf('(')).toLowerCase() + ' ';
				var fontName = listItems[0].substring(0, listItems[0].length - fontType.length + 1);

				if(this.supportedFontTypes.indexOf(fontType) > -1 && this.fontsToSkip.indexOf(':' + fontName + ':') == -1) {
					//check the height, to see if it's a font we can use
					this.fontSizer.font = this.fontSizer.value = fontName;
					this.fontSizer.height = 0;

					if (this.fontSizer.height != 0) {
						// console.log('Using font: '+fontName);

						var tRow = tdFonts.insertRow(tdFonts.rows.length);
						tRow.className = 'menuItem';
						
						var tCell = tRow.insertCell(0);
						tCell.innerText = fontName;
						tCell.style.fontFamily = fontName;
						tCell.style.fontSize = divFonttype.style.fontSize;

						if (fontName == this.currentFont) {
							this.fonttypeIndex = tdFonts.rows.length - 1;
							// tRow.className = 'menuItemSelected';
						}

					} else {
						// console.log('Cant use font: '+fontName);
					}
				}
				listItems.shift();
			}

			if (listItems.length > 0) {
				var context = this;
				setTimeout(function() { context.buildList(listItems); }, 20);
			}
		// } catch(err) {
			// console.log('buildList: '+err.name+' - '+err.message);
		// }
	},

	showFontMenu: function(id, x, y) {
		console.log('[showFontMenu]');

		if (id == -1) {
			if (fontMenu.style.display != 'none') {
				id = this.selectingFont;
			} else {
				return;
			}
		}
			
		fontMenu.style.display = (fontMenu.style.display == 'none') ? 'inline' : 'none';

		if (fontMenu.style.display == 'none') {
			console.log('[showFontMenu] hidden');

			switch (this.selectingFont) {
				case 0:
					fontDropPNG.src = 'images/dropmenu.png';
					break;
			}
			this.selectingFont = -1;
		} else {
			console.log('[showFontMenu] displayed');

			fontMenu.style.top = y;
			fontMenu.style.left = x;
			this.selectingFont = id;
			
			// console.log(tdFonts.rows(fonttypeIndex).className);
			// console.log(id);

			switch (id) {
				case 0:
					fontMenu.scrollTop = tdFonts.rows(this.fonttypeIndex).offsetTop - 65;
					tdFonts.rows(this.fonttypeIndex).className = 'menuItemSelected';
					break;
			}

			// console.log(tdFonts.rows(fonttypeIndex).className);
		}
	},

	setFont: function(index, viaKey) {
		console.log('[setFont] '+index+', '+viaKey);

		var sFont = tdFonts.rows(index).cells(0).innerText;

		var selecting = (viaKey != null) ? viaKey : this.selectingFont;
		switch (selecting) {
			case 0:
				divFonttype.style.fontFamily = sFont;
				divFonttype.innerText = sFont;
				tdFonts.rows(this.fonttypeIndex).className = 'menuItem';
				this.fonttypeIndex = index;
				tdFonts.rows(this.fonttypeIndex).className = 'menuItemSelected';
				break;
		}

		// adjust the scrollbar if needed
		if (fontMenu.scrollTop > tdFonts.rows(index).offsetTop) {
			fontMenu.scrollTop = tdFonts.rows(index).offsetTop;
		}

		if (fontMenu.scrollTop < tdFonts.rows(index).offsetTop+tdFonts.rows(index).offsetHeight-150) {
			fontMenu.scrollTop = tdFonts.rows(index).offsetTop+tdFonts.rows(index).offsetHeight-150;
		}
	},

	setFontStyle: function(i) {
		console.log('[setFontStyle]');

		switch (i) {
			case 0:
				divFonttype.style.fontWeight = divFonttypeBold.checked ? 'bold' : '';
				divFonttype.style.fontStyle = divFonttypeItalic.checked ? 'italic' : '';
				break;
		}
	},

	keyPress: function(i) {
		console.log('[keyPress]');

		switch (event.keyCode)
		{
			case 40:	//down arrow
				if (i == 0) {
					if (this.fonttypeIndex < tdFonts.rows.length-1) {
						this.setFont(this.fonttypeIndex+1, i);
					}
				}
				break;
			case 38:	//up arrow
				if (i == 0) {
					if (this.fonttypeIndex > 0) {
						this.setFont(this.fonttypeIndex-1, i);
					}
				}
				break;
			case 36:	//home
				this.setFont(0, i);
				break;
			case 35:	//end
				this.setFont(tdFonts.rows.length - 1, i);
				break;
		}
	},

	mouseOver: function(mouseEntered, id) {
		// console.log('[mouseOver]');

		var selected = (this.selectingFont == 0) ? this.fonttypeIndex : 0;

		if (mouseEntered) {
			id.className = (id.rowIndex == selected) ? 'menuItemHoverSelected' : 'menuItemHover';
		} else {
			id.className = (id.rowIndex == selected) ? 'menuItemSelected' : 'menuItem';
		}
	}
}

La modificaciones que hicimos en este archivo sirven para detectar todas las fuentes disponibles en Windows. Anteriormente, las fuentes se guardaban por default en la ruta "\Windows\fonts" y el "catalogo" de fuentes se guardaba en el registro en la siguiente ruta: "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\", pero para Windows 10 (y no se si para el 8 tambien), se cambio la ubicacion real y la del catalogo; ahora en lugar de estar en "HKLM" (HKey Local Machine), paso a almacenarse en "HKCU" (HKey Current User). Para hacer uso de cada una de las llaves, debemos de acceder a ellas por su valor hexadecimal, tomemos cómo referencia la siguiente lista:
  • HKEY_CLASSES_ROOT = 2147483648 (0x80000000)
  • HKEY_CURRENT_USER = 2147483649 (0x80000001)
  • HKEY_LOCAL_MACHINE = 2147483650 (0x80000002)
  • HKEY_USERS = 2147483651 (0x80000003)
  • HKEY_CURRENT_CONFIG = 2147483653 (0x80000005)
  • HKEY_DYN_DATA = 2147483654 (0x80000006)
Si revisas detenidamente, verás que en el código javascript hay una variable llamada "HKLM" cuyo valor corresponde a la llave "HKey Local Machine" que su vez es el número 2147483650, entonces la manera fácil de cambiar la llave a la que vamos a acceder es simplemente cambiando el valor de ésta a la del valor de la llave de destino (en este caso 2147483649).

Una vez cambiado este valor, para volver a empaquetar el gadget, debemos de usar winrar y elegir en formato "zip" y en método de compresión "No comprimir". Al archivo resultante de la compresión, simplemente le cambiamos el nombre de tal modo que la extensión en lugar de ".zip", sea ".gadget"

Después para instalarlo, simplemente hacemos doble clic en el archivo y se instalará al repositorio de gadgets.

Y bien, por ahora es todo, el siguiente post veremos como crear una versión de acuerdo al idioma que elijas y cómo agregar un par de personalizaciones para que se adapte un poco a tu gusto.

No hay comentarios. :

Publicar un comentario